blob: b54b9fa97d9a5f0c682991192384a7aa995567f8 [file] [log] [blame]
Jamie Hannaford9fdda582015-02-10 12:15:43 +01001package instances
2
3import (
4 "fmt"
5
6 "github.com/racker/perigee"
7 "github.com/rackspace/gophercloud"
Jamie Hannaford90684242015-02-10 12:46:07 +01008 "github.com/rackspace/gophercloud/pagination"
Jamie Hannaford9fdda582015-02-10 12:15:43 +01009)
10
11// CreateOptsBuilder is the top-level interface for create options.
12type CreateOptsBuilder interface {
13 ToInstanceCreateMap() (map[string]interface{}, error)
14}
15
16// DatabaseOpts is the struct responsible for configuring a database; often in
17// the context of an instance.
18type DatabaseOpts struct {
19 // Specifies the name of the database. Optional.
20 Name string
21
22 // Set of symbols and encodings. Optional; the default character set is utf8.
23 CharSet string
24
25 // Set of rules for comparing characters in a character set. Optional; the
26 // default value for collate is utf8_general_ci.
27 Collate string
28}
29
30func (opts DatabaseOpts) ToMap() (map[string]string, error) {
31 db := map[string]string{}
32 if opts.Name != "" {
33 db["name"] = opts.Name
34 }
35 if opts.CharSet != "" {
36 db["character_set"] = opts.CharSet
37 }
38 if opts.Collate != "" {
39 db["collate"] = opts.Collate
40 }
41 return db, nil
42}
43
44type DatabasesOpts []DatabaseOpts
45
46func (opts DatabasesOpts) ToMap() ([]map[string]string, error) {
47 var dbs []map[string]string
48 for _, db := range opts {
49 dbMap, err := db.ToMap()
50 if err != nil {
51 return dbs, err
52 }
53 dbs = append(dbs, dbMap)
54 }
55 return dbs, nil
56}
57
58// UserOpts is the struct responsible for configuring a user; often in the
59// context of an instance.
60type UserOpts struct {
61 // Specifies a name for the user.
62 Name string
63
64 // Specifies a password for the user.
65 Password string
66
67 // An array of databases that this user will connect to. The `name` field is
68 // the only requirement for each option.
69 Databases []DatabaseOpts
70
71 // Specifies the host from which a user is allowed to connect to the database.
72 // Possible values are a string containing an IPv4 address or "%" to allow
73 // connecting from any host. Optional; the default is "%".
74 Host string
75}
76
77func (opts UserOpts) ToMap() (map[string]interface{}, error) {
78 user := map[string]interface{}{}
79
80 if opts.Name != "" {
81 user["name"] = opts.Name
82 }
83 if opts.Password != "" {
84 user["password"] = opts.Password
85 }
86 if opts.Host != "" {
87 user["host"] = opts.Host
88 }
89
90 var dbs []map[string]string
91 for _, db := range opts.Databases {
92 dbs = append(dbs, map[string]string{"name": db.Name})
93 }
94 if len(dbs) > 0 {
95 user["databases"] = dbs
96 }
97
98 return user, nil
99}
100
101type UsersOpts []UserOpts
102
103func (opts UsersOpts) ToMap() ([]map[string]interface{}, error) {
104 var users []map[string]interface{}
105 for _, opt := range opts {
106 user, err := opt.ToMap()
107 if err != nil {
108 return users, err
109 }
110 users = append(users, user)
111 }
112 return users, nil
113}
114
115// CreateOpts is the struct responsible for configuring a new database instance.
116type CreateOpts struct {
117 // Either the integer UUID (in string form) of the flavor, or its URI
118 // reference as specified in the response from the List() call. Required.
119 FlavorRef string
120
121 // Specifies the volume size in gigabytes (GB). The value must be between 1
122 // and 300. Required.
123 Size int
124
125 // Name of the instance to create. The length of the name is limited to
126 // 255 characters and any characters are permitted. Optional.
127 Name string
128
129 // A slice of database information options.
130 Databases DatabasesOpts
131
132 // A slice of user information options.
133 Users UsersOpts
134}
135
136func (opts CreateOpts) ToInstanceCreateMap() (map[string]interface{}, error) {
137 if opts.Size > 300 || opts.Size < 1 {
138 return nil, fmt.Errorf("Size (GB) must be between 1-300")
139 }
140 if opts.FlavorRef == "" {
141 return nil, fmt.Errorf("FlavorRef is a required field")
142 }
143
144 instance := map[string]interface{}{
145 "volume": map[string]int{"size": opts.Size},
146 "flavorRef": opts.FlavorRef,
147 }
148
149 if opts.Name != "" {
150 instance["name"] = opts.Name
151 }
152 if len(opts.Databases) > 0 {
153 dbs, err := opts.Databases.ToMap()
154 if err != nil {
155 return nil, err
156 }
157 instance["databases"] = dbs
158 }
159 if len(opts.Users) > 0 {
160 users, err := opts.Users.ToMap()
161 if err != nil {
162 return nil, err
163 }
164 instance["users"] = users
165 }
166
167 return map[string]interface{}{"instance": instance}, nil
168}
169
170// Create will provision a new Database instance.
171func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
172 var res CreateResult
173
174 reqBody, err := opts.ToInstanceCreateMap()
175 if err != nil {
176 res.Err = err
177 return res
178 }
179
Jamie Hannaford90684242015-02-10 12:46:07 +0100180 resp, err := perigee.Request("POST", baseURL(client), perigee.Options{
Jamie Hannaford9fdda582015-02-10 12:15:43 +0100181 MoreHeaders: client.AuthenticatedHeaders(),
182 ReqBody: &reqBody,
183 Results: &res.Body,
184 OkCodes: []int{200},
185 })
186
187 res.Header = resp.HttpResponse.Header
188 res.Err = err
189
190 return res
191}
Jamie Hannaford90684242015-02-10 12:46:07 +0100192
193func List(client *gophercloud.ServiceClient) pagination.Pager {
194 createPageFn := func(r pagination.PageResult) pagination.Page {
195 return InstancePage{pagination.LinkedPageBase{PageResult: r}}
196 }
197
198 return pagination.NewPager(client, baseURL(client), createPageFn)
199}
Jamie Hannaford821015f2015-02-10 12:58:36 +0100200
201func Get(client *gophercloud.ServiceClient, id string) GetResult {
202 var res GetResult
203
204 resp, err := perigee.Request("GET", resourceURL(client, id), perigee.Options{
205 MoreHeaders: client.AuthenticatedHeaders(),
206 Results: &res.Body,
207 OkCodes: []int{200},
208 })
209
210 res.Header = resp.HttpResponse.Header
211 res.Err = err
212
213 return res
214}
Jamie Hannaford5b16b632015-02-10 13:36:23 +0100215
216func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
217 var res DeleteResult
218
219 resp, err := perigee.Request("DELETE", resourceURL(client, id), perigee.Options{
220 MoreHeaders: client.AuthenticatedHeaders(),
221 OkCodes: []int{202},
222 })
223
224 res.Header = resp.HttpResponse.Header
225 res.Err = err
226
227 return res
228}
Jamie Hannaford94164fa2015-02-10 13:58:45 +0100229
230func EnableRootUser(client *gophercloud.ServiceClient, id string) UserRootResult {
231 var res UserRootResult
232
233 resp, err := perigee.Request("POST", userRootURL(client, id), perigee.Options{
234 MoreHeaders: client.AuthenticatedHeaders(),
235 Results: &res.Body,
236 OkCodes: []int{200},
237 })
238
239 res.Header = resp.HttpResponse.Header
240 res.Err = err
241
242 return res
243}