blob: ff2e795e1e7b8b1b6e281233c88021ec6fb5b944 [file] [log] [blame]
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -08001package servers
2
3import (
einarf4e5fdaf2015-04-16 23:14:59 +00004 "fmt"
einarf4e5fdaf2015-04-16 23:14:59 +00005 "net/url"
Jon Perritt12395212016-02-24 10:41:17 -06006 "path"
Jon Perritt9a0980e2015-01-14 21:29:44 -07007
Jon Perritt27249f42016-02-18 10:35:59 -06008 "github.com/gophercloud/gophercloud"
9 "github.com/gophercloud/gophercloud/pagination"
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -080010)
11
Ash Wilson397c78b2014-09-25 15:19:14 -040012type serverResult struct {
Ash Wilsonf548aad2014-10-20 08:35:34 -040013 gophercloud.Result
Ash Wilson397c78b2014-09-25 15:19:14 -040014}
15
16// Extract interprets any serverResult as a Server, if possible.
17func (r serverResult) Extract() (*Server, error) {
Jon Perritt12395212016-02-24 10:41:17 -060018 var s struct {
19 Server *Server `json:"server"`
Ash Wilson397c78b2014-09-25 15:19:14 -040020 }
Jon Perritt12395212016-02-24 10:41:17 -060021 err := r.ExtractInto(&s)
22 return s.Server, err
Ash Wilson397c78b2014-09-25 15:19:14 -040023}
24
25// CreateResult temporarily contains the response from a Create call.
26type CreateResult struct {
27 serverResult
28}
29
30// GetResult temporarily contains the response from a Get call.
31type GetResult struct {
32 serverResult
33}
34
35// UpdateResult temporarily contains the response from an Update call.
36type UpdateResult struct {
37 serverResult
38}
39
Jon Perrittcc77da62014-11-16 13:14:21 -070040// DeleteResult temporarily contains the response from a Delete call.
Jamie Hannaford34732fe2014-10-27 11:29:36 +010041type DeleteResult struct {
Jon Perrittba2395e2014-10-27 15:23:21 -050042 gophercloud.ErrResult
Jamie Hannaford34732fe2014-10-27 11:29:36 +010043}
44
Ash Wilson397c78b2014-09-25 15:19:14 -040045// RebuildResult temporarily contains the response from a Rebuild call.
Jamie Hannaford01c1efe2014-10-16 15:08:59 +020046type RebuildResult struct {
Ash Wilson397c78b2014-09-25 15:19:14 -040047 serverResult
48}
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -080049
Jamie Hannaford01c1efe2014-10-16 15:08:59 +020050// ActionResult represents the result of server action operations, like reboot
51type ActionResult struct {
Jon Perrittba2395e2014-10-27 15:23:21 -050052 gophercloud.ErrResult
Jamie Hannaford01c1efe2014-10-16 15:08:59 +020053}
54
Alex Gaynor587e3e32014-11-13 10:39:09 -080055// RescueResult represents the result of a server rescue operation
Alex Gaynorfbe61bb2014-11-12 13:35:03 -080056type RescueResult struct {
57 ActionResult
Alex Gaynor7f3b06e2014-11-13 09:54:03 -080058}
59
einarf4e5fdaf2015-04-16 23:14:59 +000060// CreateImageResult represents the result of an image creation operation
61type CreateImageResult struct {
einarf2fc665e2015-04-16 20:16:21 +000062 gophercloud.Result
63}
64
einarf4e5fdaf2015-04-16 23:14:59 +000065// ExtractImageID gets the ID of the newly created server image from the header
66func (res CreateImageResult) ExtractImageID() (string, error) {
67 if res.Err != nil {
68 return "", res.Err
69 }
70 // Get the image id from the header
71 u, err := url.ParseRequestURI(res.Header.Get("Location"))
72 if err != nil {
Jon Perritt13808262016-03-09 00:50:12 -060073 return "", err
einarf4e5fdaf2015-04-16 23:14:59 +000074 }
Jon Perritt12395212016-02-24 10:41:17 -060075 imageID := path.Base(u.Path)
76 if imageID == "." || imageID == "/" {
einarf4e5fdaf2015-04-16 23:14:59 +000077 return "", fmt.Errorf("Failed to parse the ID of newly created image: %s", u)
78 }
Jon Perritt12395212016-02-24 10:41:17 -060079 return imageID, nil
einarf4e5fdaf2015-04-16 23:14:59 +000080}
81
Jon Perrittcc77da62014-11-16 13:14:21 -070082// Extract interprets any RescueResult as an AdminPass, if possible.
Alex Gaynor7f3b06e2014-11-13 09:54:03 -080083func (r RescueResult) Extract() (string, error) {
Jon Perritt12395212016-02-24 10:41:17 -060084 var s struct {
85 AdminPass string `json:"adminPass"`
Alex Gaynor7f3b06e2014-11-13 09:54:03 -080086 }
Jon Perritt12395212016-02-24 10:41:17 -060087 err := r.ExtractInto(&s)
88 return s.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.
Jon Perritt12395212016-02-24 10:41:17 -060094 ID string `json:"id"`
Ash Wilson01626a32014-09-17 10:38:07 -040095
96 // TenantID identifies the tenant owning this server resource.
Jon Perritt12395212016-02-24 10:41:17 -060097 TenantID string `json:"tenant_id"`
Ash Wilson01626a32014-09-17 10:38:07 -040098
99 // UserID uniquely identifies the user account owning the tenant.
Jon Perritt12395212016-02-24 10:41:17 -0600100 UserID string `json:"user_id"`
Ash Wilson01626a32014-09-17 10:38:07 -0400101
102 // Name contains the human-readable name for the server.
Jon Perritt12395212016-02-24 10:41:17 -0600103 Name string `json:"name"`
Ash Wilson01626a32014-09-17 10:38:07 -0400104
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.
Jon Perritt12395212016-02-24 10:41:17 -0600137 KeyName string `json:"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.
Jon Perritt12395212016-02-24 10:41:17 -0600141 AdminPass string `json:"adminPass"`
Joe Topjian978bb502015-02-12 20:55:31 +0000142
143 // SecurityGroups includes the security groups that this instance has applied to it
Jon Perritt12395212016-02-24 10:41:17 -0600144 SecurityGroups []map[string]interface{} `json:"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)
Jon Perritt12395212016-02-24 10:41:17 -0600157 return len(servers) == 0, err
Ash Wilson397c78b2014-09-25 15:19:14 -0400158}
159
160// NextPageURL uses the response's embedded link reference to navigate to the next page of results.
161func (page ServerPage) NextPageURL() (string, error) {
Jon Perritt12395212016-02-24 10:41:17 -0600162 var s struct {
163 Links []gophercloud.Link `json:"servers_links"`
Ash Wilsond27e0ff2014-09-25 11:50:31 -0400164 }
Jon Perritt12395212016-02-24 10:41:17 -0600165 err := page.ExtractInto(&s)
Ash Wilson397c78b2014-09-25 15:19:14 -0400166 if err != nil {
167 return "", err
Ash Wilsond27e0ff2014-09-25 11:50:31 -0400168 }
Jon Perritt12395212016-02-24 10:41:17 -0600169 return gophercloud.ExtractNextURL(s.Links)
Ash Wilsond27e0ff2014-09-25 11:50:31 -0400170}
171
Ash Wilson01626a32014-09-17 10:38:07 -0400172// ExtractServers interprets the results of a single page from a List() call, producing a slice of Server entities.
Jon Perritt31b66462016-02-25 22:25:30 -0600173func ExtractServers(r pagination.Page) ([]Server, error) {
Jon Perritt12395212016-02-24 10:41:17 -0600174 var s struct {
175 Servers []Server `json:"servers"`
Ash Wilson12259392014-09-17 10:50:02 -0400176 }
Jon Perritt31b66462016-02-25 22:25:30 -0600177 err := (r.(ServerPage)).ExtractInto(&s)
Jon Perritt12395212016-02-24 10:41:17 -0600178 return s.Servers, err
Samuel A. Falvo IIc007c272014-02-10 20:49:26 -0800179}
Jon Perrittcc77da62014-11-16 13:14:21 -0700180
Jon Perritt78c57ce2014-11-20 11:07:18 -0700181// MetadataResult contains the result of a call for (potentially) multiple key-value pairs.
Jon Perrittcc77da62014-11-16 13:14:21 -0700182type MetadataResult struct {
183 gophercloud.Result
184}
185
186// GetMetadataResult temporarily contains the response from a metadata Get call.
187type GetMetadataResult struct {
188 MetadataResult
189}
190
Jon Perritt789f8322014-11-21 08:20:04 -0700191// ResetMetadataResult temporarily contains the response from a metadata Reset call.
192type ResetMetadataResult struct {
Jon Perrittcc77da62014-11-16 13:14:21 -0700193 MetadataResult
194}
195
Jon Perritt78c57ce2014-11-20 11:07:18 -0700196// UpdateMetadataResult temporarily contains the response from a metadata Update call.
197type UpdateMetadataResult struct {
198 MetadataResult
Jon Perrittcc77da62014-11-16 13:14:21 -0700199}
200
Jon Perritt78c57ce2014-11-20 11:07:18 -0700201// MetadatumResult contains the result of a call for individual a single key-value pair.
202type MetadatumResult struct {
203 gophercloud.Result
204}
Jon Perrittcc77da62014-11-16 13:14:21 -0700205
Jon Perritt78c57ce2014-11-20 11:07:18 -0700206// GetMetadatumResult temporarily contains the response from a metadatum Get call.
207type GetMetadatumResult struct {
208 MetadatumResult
209}
Jon Perrittcc77da62014-11-16 13:14:21 -0700210
Jon Perritt78c57ce2014-11-20 11:07:18 -0700211// CreateMetadatumResult temporarily contains the response from a metadatum Create call.
212type CreateMetadatumResult struct {
213 MetadatumResult
214}
215
216// DeleteMetadatumResult temporarily contains the response from a metadatum Delete call.
217type DeleteMetadatumResult struct {
218 gophercloud.ErrResult
Jon Perrittcc77da62014-11-16 13:14:21 -0700219}
220
221// Extract interprets any MetadataResult as a Metadata, if possible.
222func (r MetadataResult) Extract() (map[string]string, error) {
Jon Perritt12395212016-02-24 10:41:17 -0600223 var s struct {
224 Metadata map[string]string `json:"metadata"`
Jon Perrittcc77da62014-11-16 13:14:21 -0700225 }
Jon Perritt12395212016-02-24 10:41:17 -0600226 err := r.ExtractInto(&s)
227 return s.Metadata, err
Jon Perrittcc77da62014-11-16 13:14:21 -0700228}
Jon Perritt78c57ce2014-11-20 11:07:18 -0700229
230// Extract interprets any MetadatumResult as a Metadatum, if possible.
231func (r MetadatumResult) Extract() (map[string]string, error) {
Jon Perritt12395212016-02-24 10:41:17 -0600232 var s struct {
233 Metadatum map[string]string `json:"meta"`
Jon Perritt78c57ce2014-11-20 11:07:18 -0700234 }
Jon Perritt12395212016-02-24 10:41:17 -0600235 err := r.ExtractInto(&s)
236 return s.Metadatum, err
Jon Perritt0e19f602015-01-15 09:35:46 -0700237}
Jon Perritt5cb49482015-02-19 12:19:58 -0700238
239// Address represents an IP address.
240type Address struct {
Jon Perritt12395212016-02-24 10:41:17 -0600241 Version int `json:"version"`
242 Address string `json:"addr"`
Jon Perritt5cb49482015-02-19 12:19:58 -0700243}
244
Jon Perritt04d073c2015-02-19 21:46:23 -0700245// AddressPage abstracts the raw results of making a ListAddresses() request against the API.
Jon Perritt5cb49482015-02-19 12:19:58 -0700246// As OpenStack extensions may freely alter the response bodies of structures returned
247// to the client, you may only safely access the data provided through the ExtractAddresses call.
248type AddressPage struct {
249 pagination.SinglePageBase
250}
251
Jon Perritt04d073c2015-02-19 21:46:23 -0700252// IsEmpty returns true if an AddressPage contains no networks.
Jon Perritt5cb49482015-02-19 12:19:58 -0700253func (r AddressPage) IsEmpty() (bool, error) {
254 addresses, err := ExtractAddresses(r)
Jon Perritt12395212016-02-24 10:41:17 -0600255 return len(addresses) == 0, err
Jon Perritt5cb49482015-02-19 12:19:58 -0700256}
257
Jon Perritt04d073c2015-02-19 21:46:23 -0700258// ExtractAddresses interprets the results of a single page from a ListAddresses() call,
Jon Perritt5cb49482015-02-19 12:19:58 -0700259// producing a map of addresses.
Jon Perritt31b66462016-02-25 22:25:30 -0600260func ExtractAddresses(r pagination.Page) (map[string][]Address, error) {
Jon Perritt12395212016-02-24 10:41:17 -0600261 var s struct {
262 Addresses map[string][]Address `json:"addresses"`
Jon Perritt5cb49482015-02-19 12:19:58 -0700263 }
Jon Perritt31b66462016-02-25 22:25:30 -0600264 err := (r.(AddressPage)).ExtractInto(&s)
Jon Perritt12395212016-02-24 10:41:17 -0600265 return s.Addresses, err
Jon Perritt5cb49482015-02-19 12:19:58 -0700266}
Jon Perritt04d073c2015-02-19 21:46:23 -0700267
268// NetworkAddressPage abstracts the raw results of making a ListAddressesByNetwork() request against the API.
269// As OpenStack extensions may freely alter the response bodies of structures returned
270// to the client, you may only safely access the data provided through the ExtractAddresses call.
271type NetworkAddressPage struct {
272 pagination.SinglePageBase
273}
274
275// IsEmpty returns true if a NetworkAddressPage contains no addresses.
276func (r NetworkAddressPage) IsEmpty() (bool, error) {
277 addresses, err := ExtractNetworkAddresses(r)
Jon Perritt12395212016-02-24 10:41:17 -0600278 return len(addresses) == 0, err
Jon Perritt04d073c2015-02-19 21:46:23 -0700279}
280
281// ExtractNetworkAddresses interprets the results of a single page from a ListAddressesByNetwork() call,
Jon Perrittb51ba9c2015-02-23 10:56:35 -0700282// producing a slice of addresses.
Jon Perritt31b66462016-02-25 22:25:30 -0600283func ExtractNetworkAddresses(r pagination.Page) ([]Address, error) {
Jon Perritt12395212016-02-24 10:41:17 -0600284 var s map[string][]Address
Jon Perritt31b66462016-02-25 22:25:30 -0600285 err := (r.(NetworkAddressPage)).ExtractInto(&s)
Jon Perritt04d073c2015-02-19 21:46:23 -0700286 if err != nil {
287 return nil, err
288 }
289
Jon Perrittb51ba9c2015-02-23 10:56:35 -0700290 var key string
Jon Perritt12395212016-02-24 10:41:17 -0600291 for k := range s {
Jon Perrittb51ba9c2015-02-23 10:56:35 -0700292 key = k
293 }
294
Jon Perritt12395212016-02-24 10:41:17 -0600295 return s[key], err
Jon Perritt04d073c2015-02-19 21:46:23 -0700296}