1package flavors
2
3import (
4	"encoding/json"
5	"strconv"
6
7	"github.com/gophercloud/gophercloud"
8	"github.com/gophercloud/gophercloud/pagination"
9)
10
11type commonResult struct {
12	gophercloud.Result
13}
14
15// CreateResult is the response of a Get operations. Call its Extract method to
16// interpret it as a Flavor.
17type CreateResult struct {
18	commonResult
19}
20
21// GetResult is the response of a Get operations. Call its Extract method to
22// interpret it as a Flavor.
23type GetResult struct {
24	commonResult
25}
26
27// DeleteResult is the result from a Delete operation. Call its ExtractErr
28// method to determine if the call succeeded or failed.
29type DeleteResult struct {
30	gophercloud.ErrResult
31}
32
33// Extract provides access to the individual Flavor returned by the Get and
34// Create functions.
35func (r commonResult) Extract() (*Flavor, error) {
36	var s struct {
37		Flavor *Flavor `json:"flavor"`
38	}
39	err := r.ExtractInto(&s)
40	return s.Flavor, err
41}
42
43// Flavor represent (virtual) hardware configurations for server resources
44// in a region.
45type Flavor struct {
46	// ID is the flavor's unique ID.
47	ID string `json:"id"`
48
49	// Disk is the amount of root disk, measured in GB.
50	Disk int `json:"disk"`
51
52	// RAM is the amount of memory, measured in MB.
53	RAM int `json:"ram"`
54
55	// Name is the name of the flavor.
56	Name string `json:"name"`
57
58	// RxTxFactor describes bandwidth alterations of the flavor.
59	RxTxFactor float64 `json:"rxtx_factor"`
60
61	// Swap is the amount of swap space, measured in MB.
62	Swap int `json:"-"`
63
64	// VCPUs indicates how many (virtual) CPUs are available for this flavor.
65	VCPUs int `json:"vcpus"`
66
67	// IsPublic indicates whether the flavor is public.
68	IsPublic bool `json:"os-flavor-access:is_public"`
69
70	// Ephemeral is the amount of ephemeral disk space, measured in GB.
71	Ephemeral int `json:"OS-FLV-EXT-DATA:ephemeral"`
72}
73
74func (r *Flavor) UnmarshalJSON(b []byte) error {
75	type tmp Flavor
76	var s struct {
77		tmp
78		Swap interface{} `json:"swap"`
79	}
80	err := json.Unmarshal(b, &s)
81	if err != nil {
82		return err
83	}
84
85	*r = Flavor(s.tmp)
86
87	switch t := s.Swap.(type) {
88	case float64:
89		r.Swap = int(t)
90	case string:
91		switch t {
92		case "":
93			r.Swap = 0
94		default:
95			swap, err := strconv.ParseFloat(t, 64)
96			if err != nil {
97				return err
98			}
99			r.Swap = int(swap)
100		}
101	}
102
103	return nil
104}
105
106// FlavorPage contains a single page of all flavors from a ListDetails call.
107type FlavorPage struct {
108	pagination.LinkedPageBase
109}
110
111// IsEmpty determines if a FlavorPage contains any results.
112func (page FlavorPage) IsEmpty() (bool, error) {
113	flavors, err := ExtractFlavors(page)
114	return len(flavors) == 0, err
115}
116
117// NextPageURL uses the response's embedded link reference to navigate to the
118// next page of results.
119func (page FlavorPage) NextPageURL() (string, error) {
120	var s struct {
121		Links []gophercloud.Link `json:"flavors_links"`
122	}
123	err := page.ExtractInto(&s)
124	if err != nil {
125		return "", err
126	}
127	return gophercloud.ExtractNextURL(s.Links)
128}
129
130// ExtractFlavors provides access to the list of flavors in a page acquired
131// from the ListDetail operation.
132func ExtractFlavors(r pagination.Page) ([]Flavor, error) {
133	var s struct {
134		Flavors []Flavor `json:"flavors"`
135	}
136	err := (r.(FlavorPage)).ExtractInto(&s)
137	return s.Flavors, err
138}
139
140// AccessPage contains a single page of all FlavorAccess entries for a flavor.
141type AccessPage struct {
142	pagination.SinglePageBase
143}
144
145// IsEmpty indicates whether an AccessPage is empty.
146func (page AccessPage) IsEmpty() (bool, error) {
147	v, err := ExtractAccesses(page)
148	return len(v) == 0, err
149}
150
151// ExtractAccesses interprets a page of results as a slice of FlavorAccess.
152func ExtractAccesses(r pagination.Page) ([]FlavorAccess, error) {
153	var s struct {
154		FlavorAccesses []FlavorAccess `json:"flavor_access"`
155	}
156	err := (r.(AccessPage)).ExtractInto(&s)
157	return s.FlavorAccesses, err
158}
159
160type accessResult struct {
161	gophercloud.Result
162}
163
164// AddAccessResult is the response of an AddAccess operation. Call its
165// Extract method to interpret it as a slice of FlavorAccess.
166type AddAccessResult struct {
167	accessResult
168}
169
170// RemoveAccessResult is the response of a RemoveAccess operation. Call its
171// Extract method to interpret it as a slice of FlavorAccess.
172type RemoveAccessResult struct {
173	accessResult
174}
175
176// Extract provides access to the result of an access create or delete.
177// The result will be all accesses that the flavor has.
178func (r accessResult) Extract() ([]FlavorAccess, error) {
179	var s struct {
180		FlavorAccesses []FlavorAccess `json:"flavor_access"`
181	}
182	err := r.ExtractInto(&s)
183	return s.FlavorAccesses, err
184}
185
186// FlavorAccess represents an ACL of tenant access to a specific Flavor.
187type FlavorAccess struct {
188	// FlavorID is the unique ID of the flavor.
189	FlavorID string `json:"flavor_id"`
190
191	// TenantID is the unique ID of the tenant.
192	TenantID string `json:"tenant_id"`
193}
194
195// Extract interprets any extraSpecsResult as ExtraSpecs, if possible.
196func (r extraSpecsResult) Extract() (map[string]string, error) {
197	var s struct {
198		ExtraSpecs map[string]string `json:"extra_specs"`
199	}
200	err := r.ExtractInto(&s)
201	return s.ExtraSpecs, err
202}
203
204// extraSpecsResult contains the result of a call for (potentially) multiple
205// key-value pairs. Call its Extract method to interpret it as a
206// map[string]interface.
207type extraSpecsResult struct {
208	gophercloud.Result
209}
210
211// ListExtraSpecsResult contains the result of a Get operation. Call its Extract
212// method to interpret it as a map[string]interface.
213type ListExtraSpecsResult struct {
214	extraSpecsResult
215}
216
217// CreateExtraSpecResult contains the result of a Create operation. Call its
218// Extract method to interpret it as a map[string]interface.
219type CreateExtraSpecsResult struct {
220	extraSpecsResult
221}
222
223// extraSpecResult contains the result of a call for individual a single
224// key-value pair.
225type extraSpecResult struct {
226	gophercloud.Result
227}
228
229// GetExtraSpecResult contains the result of a Get operation. Call its Extract
230// method to interpret it as a map[string]interface.
231type GetExtraSpecResult struct {
232	extraSpecResult
233}
234
235// UpdateExtraSpecResult contains the result of an Update operation. Call its
236// Extract method to interpret it as a map[string]interface.
237type UpdateExtraSpecResult struct {
238	extraSpecResult
239}
240
241// DeleteExtraSpecResult contains the result of a Delete operation. Call its
242// ExtractErr method to determine if the call succeeded or failed.
243type DeleteExtraSpecResult struct {
244	gophercloud.ErrResult
245}
246
247// Extract interprets any extraSpecResult as an ExtraSpec, if possible.
248func (r extraSpecResult) Extract() (map[string]string, error) {
249	var s map[string]string
250	err := r.ExtractInto(&s)
251	return s, err
252}
253