blob: e2be6baa785cbfb233ddf29ba5c930223d3b5eee [file] [log] [blame]
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -08001package servers
2
3import (
Jon Perritt9a0980e2015-01-14 21:29:44 -07004 "reflect"
5
Samuel A. Falvo IIe246ac02014-02-13 23:20:09 -08006 "github.com/mitchellh/mapstructure"
Ash Wilsond27e0ff2014-09-25 11:50:31 -04007 "github.com/rackspace/gophercloud"
Ash Wilson01626a32014-09-17 10:38:07 -04008 "github.com/rackspace/gophercloud/pagination"
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -08009)
10
Ash Wilson397c78b2014-09-25 15:19:14 -040011type serverResult struct {
Ash Wilsonf548aad2014-10-20 08:35:34 -040012 gophercloud.Result
Ash Wilson397c78b2014-09-25 15:19:14 -040013}
14
15// Extract interprets any serverResult as a Server, if possible.
16func (r serverResult) Extract() (*Server, error) {
17 if r.Err != nil {
18 return nil, r.Err
19 }
20
21 var response struct {
22 Server Server `mapstructure:"server"`
23 }
24
Jon Perritt9a0980e2015-01-14 21:29:44 -070025 config := &mapstructure.DecoderConfig{
Jon Perritt0e19f602015-01-15 09:35:46 -070026 DecodeHook: toMapFromString,
27 Result: &response,
Jon Perritt9a0980e2015-01-14 21:29:44 -070028 }
29 decoder, err := mapstructure.NewDecoder(config)
30 if err != nil {
31 return nil, err
32 }
33
34 err = decoder.Decode(r.Body)
35 if err != nil {
36 return nil, err
37 }
38
39 return &response.Server, nil
Ash Wilson397c78b2014-09-25 15:19:14 -040040}
41
42// CreateResult temporarily contains the response from a Create call.
43type CreateResult struct {
44 serverResult
45}
46
47// GetResult temporarily contains the response from a Get call.
48type GetResult struct {
49 serverResult
50}
51
52// UpdateResult temporarily contains the response from an Update call.
53type UpdateResult struct {
54 serverResult
55}
56
Jon Perrittcc77da62014-11-16 13:14:21 -070057// DeleteResult temporarily contains the response from a Delete call.
Jamie Hannaford34732fe2014-10-27 11:29:36 +010058type DeleteResult struct {
Jon Perrittba2395e2014-10-27 15:23:21 -050059 gophercloud.ErrResult
Jamie Hannaford34732fe2014-10-27 11:29:36 +010060}
61
Ash Wilson397c78b2014-09-25 15:19:14 -040062// RebuildResult temporarily contains the response from a Rebuild call.
Jamie Hannaford01c1efe2014-10-16 15:08:59 +020063type RebuildResult struct {
Ash Wilson397c78b2014-09-25 15:19:14 -040064 serverResult
65}
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -080066
Jamie Hannaford01c1efe2014-10-16 15:08:59 +020067// ActionResult represents the result of server action operations, like reboot
68type ActionResult struct {
Jon Perrittba2395e2014-10-27 15:23:21 -050069 gophercloud.ErrResult
Jamie Hannaford01c1efe2014-10-16 15:08:59 +020070}
71
Alex Gaynor587e3e32014-11-13 10:39:09 -080072// RescueResult represents the result of a server rescue operation
Alex Gaynorfbe61bb2014-11-12 13:35:03 -080073type RescueResult struct {
74 ActionResult
Alex Gaynor7f3b06e2014-11-13 09:54:03 -080075}
76
Jon Perrittcc77da62014-11-16 13:14:21 -070077// Extract interprets any RescueResult as an AdminPass, if possible.
Alex Gaynor7f3b06e2014-11-13 09:54:03 -080078func (r RescueResult) Extract() (string, error) {
79 if r.Err != nil {
Alex Gaynor94a28aa2014-11-13 10:09:56 -080080 return "", r.Err
Alex Gaynor7f3b06e2014-11-13 09:54:03 -080081 }
82
83 var response struct {
84 AdminPass string `mapstructure:"adminPass"`
85 }
86
87 err := mapstructure.Decode(r.Body, &response)
Alex Gaynor94a28aa2014-11-13 10:09:56 -080088 return response.AdminPass, err
Alex Gaynorfbe61bb2014-11-12 13:35:03 -080089}
90
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -080091// Server exposes only the standard OpenStack fields corresponding to a given server on the user's account.
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -080092type Server struct {
Ash Wilson01626a32014-09-17 10:38:07 -040093 // ID uniquely identifies this server amongst all other servers, including those not accessible to the current tenant.
94 ID string
95
96 // TenantID identifies the tenant owning this server resource.
97 TenantID string `mapstructure:"tenant_id"`
98
99 // UserID uniquely identifies the user account owning the tenant.
100 UserID string `mapstructure:"user_id"`
101
102 // Name contains the human-readable name for the server.
103 Name string
104
105 // Updated and Created contain ISO-8601 timestamps of when the state of the server last changed, and when it was created.
106 Updated string
107 Created string
108
109 HostID string
110
111 // Status contains the current operational status of the server, such as IN_PROGRESS or ACTIVE.
112 Status string
113
114 // Progress ranges from 0..100.
115 // A request made against the server completes only once Progress reaches 100.
116 Progress int
117
118 // AccessIPv4 and AccessIPv6 contain the IP addresses of the server, suitable for remote access for administration.
Jamie Hannaford908e1e92014-10-27 14:41:17 +0100119 AccessIPv4, AccessIPv6 string
Ash Wilson01626a32014-09-17 10:38:07 -0400120
121 // Image refers to a JSON object, which itself indicates the OS image used to deploy the server.
122 Image map[string]interface{}
123
124 // Flavor refers to a JSON object, which itself indicates the hardware configuration of the deployed server.
125 Flavor map[string]interface{}
126
127 // Addresses includes a list of all IP addresses assigned to the server, keyed by pool.
Ash Wilson01626a32014-09-17 10:38:07 -0400128 Addresses map[string]interface{}
129
130 // Metadata includes a list of all user-specified key-value pairs attached to the server.
131 Metadata map[string]interface{}
132
133 // Links includes HTTP references to the itself, useful for passing along to other APIs that might want a server reference.
134 Links []interface{}
135
Ash Wilsonad21c712014-09-25 10:15:22 -0400136 // KeyName indicates which public key was injected into the server on launch.
Ash Wilson69b144f2014-10-21 14:03:52 -0400137 KeyName string `json:"key_name" mapstructure:"key_name"`
Ash Wilsonad21c712014-09-25 10:15:22 -0400138
Ash Wilson01626a32014-09-17 10:38:07 -0400139 // AdminPass will generally be empty (""). However, it will contain the administrative password chosen when provisioning a new server without a set AdminPass setting in the first place.
140 // Note that this is the ONLY time this field will be valid.
Ash Wilson69b144f2014-10-21 14:03:52 -0400141 AdminPass string `json:"adminPass" mapstructure:"adminPass"`
Joe Topjian978bb502015-02-12 20:55:31 +0000142
143 // SecurityGroups includes the security groups that this instance has applied to it
144 SecurityGroups []map[string]interface{} `json:"security_groups" mapstructure:"security_groups"`
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -0800145}
146
Ash Wilson397c78b2014-09-25 15:19:14 -0400147// ServerPage abstracts the raw results of making a List() request against the API.
148// As OpenStack extensions may freely alter the response bodies of structures returned to the client, you may only safely access the
149// data provided through the ExtractServers call.
150type ServerPage struct {
151 pagination.LinkedPageBase
Ash Wilsonf57381e2014-09-25 13:21:34 -0400152}
153
Ash Wilson397c78b2014-09-25 15:19:14 -0400154// IsEmpty returns true if a page contains no Server results.
155func (page ServerPage) IsEmpty() (bool, error) {
156 servers, err := ExtractServers(page)
157 if err != nil {
158 return true, err
159 }
160 return len(servers) == 0, nil
161}
162
163// NextPageURL uses the response's embedded link reference to navigate to the next page of results.
164func (page ServerPage) NextPageURL() (string, error) {
Ash Wilson397c78b2014-09-25 15:19:14 -0400165 type resp struct {
Jamie Hannaforda581acd2014-10-08 17:14:13 +0200166 Links []gophercloud.Link `mapstructure:"servers_links"`
Ash Wilsond27e0ff2014-09-25 11:50:31 -0400167 }
168
Ash Wilson397c78b2014-09-25 15:19:14 -0400169 var r resp
170 err := mapstructure.Decode(page.Body, &r)
171 if err != nil {
172 return "", err
Ash Wilsond27e0ff2014-09-25 11:50:31 -0400173 }
174
Jamie Hannaforda581acd2014-10-08 17:14:13 +0200175 return gophercloud.ExtractNextURL(r.Links)
Ash Wilsond27e0ff2014-09-25 11:50:31 -0400176}
177
Ash Wilson01626a32014-09-17 10:38:07 -0400178// ExtractServers interprets the results of a single page from a List() call, producing a slice of Server entities.
179func ExtractServers(page pagination.Page) ([]Server, error) {
Ash Wilson397c78b2014-09-25 15:19:14 -0400180 casted := page.(ServerPage).Body
Ash Wilson12259392014-09-17 10:50:02 -0400181
182 var response struct {
183 Servers []Server `mapstructure:"servers"`
184 }
Jon Perritt9a0980e2015-01-14 21:29:44 -0700185
186 config := &mapstructure.DecoderConfig{
Jon Perritt0e19f602015-01-15 09:35:46 -0700187 DecodeHook: toMapFromString,
188 Result: &response,
Jon Perritt9a0980e2015-01-14 21:29:44 -0700189 }
190 decoder, err := mapstructure.NewDecoder(config)
191 if err != nil {
192 return nil, err
193 }
194
195 err = decoder.Decode(casted)
196
Ash Wilson12259392014-09-17 10:50:02 -0400197 return response.Servers, err
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -0800198}
Jon Perrittcc77da62014-11-16 13:14:21 -0700199
Jon Perritt78c57ce2014-11-20 11:07:18 -0700200// MetadataResult contains the result of a call for (potentially) multiple key-value pairs.
Jon Perrittcc77da62014-11-16 13:14:21 -0700201type MetadataResult struct {
202 gophercloud.Result
203}
204
205// GetMetadataResult temporarily contains the response from a metadata Get call.
206type GetMetadataResult struct {
207 MetadataResult
208}
209
Jon Perritt789f8322014-11-21 08:20:04 -0700210// ResetMetadataResult temporarily contains the response from a metadata Reset call.
211type ResetMetadataResult struct {
Jon Perrittcc77da62014-11-16 13:14:21 -0700212 MetadataResult
213}
214
Jon Perritt78c57ce2014-11-20 11:07:18 -0700215// UpdateMetadataResult temporarily contains the response from a metadata Update call.
216type UpdateMetadataResult struct {
217 MetadataResult
Jon Perrittcc77da62014-11-16 13:14:21 -0700218}
219
Jon Perritt78c57ce2014-11-20 11:07:18 -0700220// MetadatumResult contains the result of a call for individual a single key-value pair.
221type MetadatumResult struct {
222 gophercloud.Result
223}
Jon Perrittcc77da62014-11-16 13:14:21 -0700224
Jon Perritt78c57ce2014-11-20 11:07:18 -0700225// GetMetadatumResult temporarily contains the response from a metadatum Get call.
226type GetMetadatumResult struct {
227 MetadatumResult
228}
Jon Perrittcc77da62014-11-16 13:14:21 -0700229
Jon Perritt78c57ce2014-11-20 11:07:18 -0700230// CreateMetadatumResult temporarily contains the response from a metadatum Create call.
231type CreateMetadatumResult struct {
232 MetadatumResult
233}
234
235// DeleteMetadatumResult temporarily contains the response from a metadatum Delete call.
236type DeleteMetadatumResult struct {
237 gophercloud.ErrResult
Jon Perrittcc77da62014-11-16 13:14:21 -0700238}
239
240// Extract interprets any MetadataResult as a Metadata, if possible.
241func (r MetadataResult) Extract() (map[string]string, error) {
242 if r.Err != nil {
243 return nil, r.Err
244 }
245
246 var response struct {
Jon Perritt78c57ce2014-11-20 11:07:18 -0700247 Metadata map[string]string `mapstructure:"metadata"`
Jon Perrittcc77da62014-11-16 13:14:21 -0700248 }
249
250 err := mapstructure.Decode(r.Body, &response)
251 return response.Metadata, err
252}
Jon Perritt78c57ce2014-11-20 11:07:18 -0700253
254// Extract interprets any MetadatumResult as a Metadatum, if possible.
255func (r MetadatumResult) Extract() (map[string]string, error) {
256 if r.Err != nil {
257 return nil, r.Err
258 }
259
260 var response struct {
261 Metadatum map[string]string `mapstructure:"meta"`
262 }
263
264 err := mapstructure.Decode(r.Body, &response)
265 return response.Metadatum, err
266}
Jon Perritt0e19f602015-01-15 09:35:46 -0700267
268func toMapFromString(from reflect.Kind, to reflect.Kind, data interface{}) (interface{}, error) {
269 if (from == reflect.String) && (to == reflect.Map) {
270 return map[string]interface{}{}, nil
271 }
272 return data, nil
273}
Jon Perritt5cb49482015-02-19 12:19:58 -0700274
275// Address represents an IP address.
276type Address struct {
277 Version int `mapstructure:"version"`
278 Address string `mapstructure:"addr"`
279}
280
Jon Perritt04d073c2015-02-19 21:46:23 -0700281// AddressPage abstracts the raw results of making a ListAddresses() request against the API.
Jon Perritt5cb49482015-02-19 12:19:58 -0700282// As OpenStack extensions may freely alter the response bodies of structures returned
283// to the client, you may only safely access the data provided through the ExtractAddresses call.
284type AddressPage struct {
285 pagination.SinglePageBase
286}
287
Jon Perritt04d073c2015-02-19 21:46:23 -0700288// IsEmpty returns true if an AddressPage contains no networks.
Jon Perritt5cb49482015-02-19 12:19:58 -0700289func (r AddressPage) IsEmpty() (bool, error) {
290 addresses, err := ExtractAddresses(r)
291 if err != nil {
292 return true, err
293 }
294 return len(addresses) == 0, nil
295}
296
Jon Perritt04d073c2015-02-19 21:46:23 -0700297// ExtractAddresses interprets the results of a single page from a ListAddresses() call,
Jon Perritt5cb49482015-02-19 12:19:58 -0700298// producing a map of addresses.
299func ExtractAddresses(page pagination.Page) (map[string][]Address, error) {
300 casted := page.(AddressPage).Body
301
302 var response struct {
303 Addresses map[string][]Address `mapstructure:"addresses"`
304 }
305
306 err := mapstructure.Decode(casted, &response)
307 if err != nil {
308 return nil, err
309 }
310
311 return response.Addresses, err
312}
Jon Perritt04d073c2015-02-19 21:46:23 -0700313
314// NetworkAddressPage abstracts the raw results of making a ListAddressesByNetwork() request against the API.
315// As OpenStack extensions may freely alter the response bodies of structures returned
316// to the client, you may only safely access the data provided through the ExtractAddresses call.
317type NetworkAddressPage struct {
318 pagination.SinglePageBase
319}
320
321// IsEmpty returns true if a NetworkAddressPage contains no addresses.
322func (r NetworkAddressPage) IsEmpty() (bool, error) {
323 addresses, err := ExtractNetworkAddresses(r)
324 if err != nil {
325 return true, err
326 }
327 return len(addresses) == 0, nil
328}
329
330// ExtractNetworkAddresses interprets the results of a single page from a ListAddressesByNetwork() call,
Jon Perrittb51ba9c2015-02-23 10:56:35 -0700331// producing a slice of addresses.
332func ExtractNetworkAddresses(page pagination.Page) ([]Address, error) {
Jon Perritt04d073c2015-02-19 21:46:23 -0700333 casted := page.(NetworkAddressPage).Body
334
335 var response map[string][]Address
336 err := mapstructure.Decode(casted, &response)
337 if err != nil {
338 return nil, err
339 }
340
Jon Perrittb51ba9c2015-02-23 10:56:35 -0700341 var key string
342 for k := range response {
343 key = k
344 }
345
346 return response[key], err
Jon Perritt04d073c2015-02-19 21:46:23 -0700347}