blob: 35b9f9a1df200fe04ef3967cf8277f398f2ca55a [file] [log] [blame]
Jamie Hannaford9fdda582015-02-10 12:15:43 +01001package instances
2
3import (
4 "fmt"
5
Jon Perritt27249f42016-02-18 10:35:59 -06006 "github.com/gophercloud/gophercloud"
7 db "github.com/gophercloud/gophercloud/openstack/db/v1/databases"
8 "github.com/gophercloud/gophercloud/openstack/db/v1/users"
9 "github.com/gophercloud/gophercloud/pagination"
Jamie Hannaford9fdda582015-02-10 12:15:43 +010010)
11
12// CreateOptsBuilder is the top-level interface for create options.
13type CreateOptsBuilder interface {
14 ToInstanceCreateMap() (map[string]interface{}, error)
15}
16
Jamie Hannaford99eced52015-03-02 15:24:22 +010017// DatastoreOpts represents the configuration for how an instance stores data.
18type DatastoreOpts struct {
19 Version string
20 Type string
21}
22
23func (opts DatastoreOpts) ToMap() (map[string]string, error) {
24 return map[string]string{
25 "version": opts.Version,
26 "type": opts.Type,
27 }, nil
28}
29
Jamie Hannaford9fdda582015-02-10 12:15:43 +010030// CreateOpts is the struct responsible for configuring a new database instance.
31type CreateOpts struct {
32 // Either the integer UUID (in string form) of the flavor, or its URI
33 // reference as specified in the response from the List() call. Required.
34 FlavorRef string
35
36 // Specifies the volume size in gigabytes (GB). The value must be between 1
37 // and 300. Required.
38 Size int
39
40 // Name of the instance to create. The length of the name is limited to
41 // 255 characters and any characters are permitted. Optional.
42 Name string
43
44 // A slice of database information options.
Jamie Hannaford2e695a32015-11-16 16:36:10 +010045 Databases db.CreateOptsBuilder
Jamie Hannaford9fdda582015-02-10 12:15:43 +010046
47 // A slice of user information options.
Jamie Hannaford2e695a32015-11-16 16:36:10 +010048 Users users.CreateOptsBuilder
Jamie Hannaford99eced52015-03-02 15:24:22 +010049
50 // Options to configure the type of datastore the instance will use. This is
51 // optional, and if excluded will default to MySQL.
52 Datastore *DatastoreOpts
Jamie Hannaford9fdda582015-02-10 12:15:43 +010053}
54
Jamie Hannaford9793d942015-02-18 15:13:20 +010055// ToInstanceCreateMap will render a JSON map.
Jamie Hannaford9fdda582015-02-10 12:15:43 +010056func (opts CreateOpts) ToInstanceCreateMap() (map[string]interface{}, error) {
57 if opts.Size > 300 || opts.Size < 1 {
58 return nil, fmt.Errorf("Size (GB) must be between 1-300")
59 }
60 if opts.FlavorRef == "" {
61 return nil, fmt.Errorf("FlavorRef is a required field")
62 }
63
64 instance := map[string]interface{}{
65 "volume": map[string]int{"size": opts.Size},
66 "flavorRef": opts.FlavorRef,
67 }
68
69 if opts.Name != "" {
70 instance["name"] = opts.Name
71 }
Jamie Hannaford2e695a32015-11-16 16:36:10 +010072 if opts.Databases != nil {
Jamie Hannaford56d0c2e2015-02-12 11:50:18 +010073 dbs, err := opts.Databases.ToDBCreateMap()
Jamie Hannaford9fdda582015-02-10 12:15:43 +010074 if err != nil {
75 return nil, err
76 }
Jamie Hannaford56d0c2e2015-02-12 11:50:18 +010077 instance["databases"] = dbs["databases"]
Jamie Hannaford9fdda582015-02-10 12:15:43 +010078 }
Jamie Hannaford2e695a32015-11-16 16:36:10 +010079 if opts.Users != nil {
Jamie Hannaford2ca55d82015-02-12 14:21:55 +010080 users, err := opts.Users.ToUserCreateMap()
Jamie Hannaford9fdda582015-02-10 12:15:43 +010081 if err != nil {
82 return nil, err
83 }
Jamie Hannaford2ca55d82015-02-12 14:21:55 +010084 instance["users"] = users["users"]
Jamie Hannaford9fdda582015-02-10 12:15:43 +010085 }
86
87 return map[string]interface{}{"instance": instance}, nil
88}
89
Jamie Hannaford56d0c2e2015-02-12 11:50:18 +010090// Create asynchronously provisions a new database instance. It requires the
91// user to specify a flavor and a volume size. The API service then provisions
92// the instance with the requested flavor and sets up a volume of the specified
93// size, which is the storage for the database instance.
94//
95// Although this call only allows the creation of 1 instance per request, you
96// can create an instance with multiple databases and users. The default
97// binding for a MySQL instance is port 3306.
Jamie Hannaford9fdda582015-02-10 12:15:43 +010098func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
99 var res CreateResult
100
101 reqBody, err := opts.ToInstanceCreateMap()
102 if err != nil {
103 res.Err = err
104 return res
105 }
106
Jamie Hannaforda50d1352015-02-18 11:38:38 +0100107 _, res.Err = client.Request("POST", baseURL(client), gophercloud.RequestOpts{
108 JSONBody: &reqBody,
109 JSONResponse: &res.Body,
110 OkCodes: []int{200},
Jamie Hannaford9fdda582015-02-10 12:15:43 +0100111 })
112
Jamie Hannaford9fdda582015-02-10 12:15:43 +0100113 return res
114}
Jamie Hannaford90684242015-02-10 12:46:07 +0100115
Jamie Hannaford56d0c2e2015-02-12 11:50:18 +0100116// List retrieves the status and information for all database instances.
Jamie Hannaford90684242015-02-10 12:46:07 +0100117func List(client *gophercloud.ServiceClient) pagination.Pager {
118 createPageFn := func(r pagination.PageResult) pagination.Page {
119 return InstancePage{pagination.LinkedPageBase{PageResult: r}}
120 }
121
122 return pagination.NewPager(client, baseURL(client), createPageFn)
123}
Jamie Hannaford821015f2015-02-10 12:58:36 +0100124
Jamie Hannaford56d0c2e2015-02-12 11:50:18 +0100125// Get retrieves the status and information for a specified database instance.
Jamie Hannaford821015f2015-02-10 12:58:36 +0100126func Get(client *gophercloud.ServiceClient, id string) GetResult {
127 var res GetResult
128
Jamie Hannaforda50d1352015-02-18 11:38:38 +0100129 _, res.Err = client.Request("GET", resourceURL(client, id), gophercloud.RequestOpts{
130 JSONResponse: &res.Body,
131 OkCodes: []int{200},
Jamie Hannaford821015f2015-02-10 12:58:36 +0100132 })
133
Jamie Hannaford821015f2015-02-10 12:58:36 +0100134 return res
135}
Jamie Hannaford5b16b632015-02-10 13:36:23 +0100136
Jamie Hannaford56d0c2e2015-02-12 11:50:18 +0100137// Delete permanently destroys the database instance.
Jamie Hannaford5b16b632015-02-10 13:36:23 +0100138func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
139 var res DeleteResult
140
Jamie Hannaforda50d1352015-02-18 11:38:38 +0100141 _, res.Err = client.Request("DELETE", resourceURL(client, id), gophercloud.RequestOpts{
142 OkCodes: []int{202},
Jamie Hannaford5b16b632015-02-10 13:36:23 +0100143 })
144
Jamie Hannaford5b16b632015-02-10 13:36:23 +0100145 return res
146}
Jamie Hannaford94164fa2015-02-10 13:58:45 +0100147
Jamie Hannaford56d0c2e2015-02-12 11:50:18 +0100148// EnableRootUser enables the login from any host for the root user and
149// provides the user with a generated root password.
Jamie Hannaford94164fa2015-02-10 13:58:45 +0100150func EnableRootUser(client *gophercloud.ServiceClient, id string) UserRootResult {
151 var res UserRootResult
152
Jamie Hannaforda50d1352015-02-18 11:38:38 +0100153 _, res.Err = client.Request("POST", userRootURL(client, id), gophercloud.RequestOpts{
154 JSONResponse: &res.Body,
155 OkCodes: []int{200},
Jamie Hannaford94164fa2015-02-10 13:58:45 +0100156 })
157
Jamie Hannaford94164fa2015-02-10 13:58:45 +0100158 return res
159}
Jamie Hannaforda74d4252015-02-10 15:35:01 +0100160
Jamie Hannaford56d0c2e2015-02-12 11:50:18 +0100161// IsRootEnabled checks an instance to see if root access is enabled. It returns
162// True if root user is enabled for the specified database instance or False
163// otherwise.
Jamie Hannaforda74d4252015-02-10 15:35:01 +0100164func IsRootEnabled(client *gophercloud.ServiceClient, id string) (bool, error) {
165 var res gophercloud.Result
166
Jamie Hannaforda50d1352015-02-18 11:38:38 +0100167 _, err := client.Request("GET", userRootURL(client, id), gophercloud.RequestOpts{
168 JSONResponse: &res.Body,
169 OkCodes: []int{200},
Jamie Hannaforda74d4252015-02-10 15:35:01 +0100170 })
171
172 return res.Body.(map[string]interface{})["rootEnabled"] == true, err
173}
Jamie Hannaford219ca592015-02-10 15:59:05 +0100174
Jamie Hannaford75e8cc42015-11-16 14:09:25 +0100175// Restart will restart only the MySQL Instance. Restarting MySQL will
Jamie Hannaford56d0c2e2015-02-12 11:50:18 +0100176// erase any dynamic configuration settings that you have made within MySQL.
177// The MySQL service will be unavailable until the instance restarts.
Jamie Hannaford75e8cc42015-11-16 14:09:25 +0100178func Restart(client *gophercloud.ServiceClient, id string) ActionResult {
Jamie Hannaford219ca592015-02-10 15:59:05 +0100179 var res ActionResult
180
Jamie Hannaforda50d1352015-02-18 11:38:38 +0100181 _, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
Jamie Hannafordd2b755f2015-10-07 14:01:57 +0200182 JSONBody: map[string]interface{}{"restart": struct{}{}},
Jamie Hannaforda50d1352015-02-18 11:38:38 +0100183 OkCodes: []int{202},
Jamie Hannaford219ca592015-02-10 15:59:05 +0100184 })
185
Jamie Hannaford219ca592015-02-10 15:59:05 +0100186 return res
187}
188
Jamie Hannaford75e8cc42015-11-16 14:09:25 +0100189// Resize changes the memory size of the instance, assuming a valid
Jamie Hannaford56d0c2e2015-02-12 11:50:18 +0100190// flavorRef is provided. It will also restart the MySQL service.
Jamie Hannaford75e8cc42015-11-16 14:09:25 +0100191func Resize(client *gophercloud.ServiceClient, id, flavorRef string) ActionResult {
Jamie Hannaford219ca592015-02-10 15:59:05 +0100192 var res ActionResult
193
Jamie Hannaford7d51cf12015-02-25 14:50:06 +0100194 type resize struct {
195 FlavorRef string `json:"flavorRef"`
Jamie Hannaford219ca592015-02-10 15:59:05 +0100196 }
197
Jamie Hannaford7d51cf12015-02-25 14:50:06 +0100198 type req struct {
199 Resize resize `json:"resize"`
200 }
201
202 reqBody := req{Resize: resize{FlavorRef: flavorRef}}
203
Jamie Hannaforda50d1352015-02-18 11:38:38 +0100204 _, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
205 JSONBody: reqBody,
206 OkCodes: []int{202},
Jamie Hannaford219ca592015-02-10 15:59:05 +0100207 })
208
Jamie Hannaford219ca592015-02-10 15:59:05 +0100209 return res
210}
211
Jamie Hannaford56d0c2e2015-02-12 11:50:18 +0100212// ResizeVolume will resize the attached volume for an instance. It supports
213// only increasing the volume size and does not support decreasing the size.
214// The volume size is in gigabytes (GB) and must be an integer.
Jamie Hannaford219ca592015-02-10 15:59:05 +0100215func ResizeVolume(client *gophercloud.ServiceClient, id string, size int) ActionResult {
216 var res ActionResult
217
Jamie Hannaford7d51cf12015-02-25 14:50:06 +0100218 type volume struct {
219 Size int `json:"size"`
Jamie Hannaford219ca592015-02-10 15:59:05 +0100220 }
221
Jamie Hannaford7d51cf12015-02-25 14:50:06 +0100222 type resize struct {
223 Volume volume `json:"volume"`
224 }
225
226 type req struct {
227 Resize resize `json:"resize"`
228 }
229
230 reqBody := req{Resize: resize{Volume: volume{Size: size}}}
231
Jamie Hannaforda50d1352015-02-18 11:38:38 +0100232 _, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
233 JSONBody: reqBody,
234 OkCodes: []int{202},
Jamie Hannaford219ca592015-02-10 15:59:05 +0100235 })
236
Jamie Hannaford219ca592015-02-10 15:59:05 +0100237 return res
238}