1package hypervisors
2
3import (
4	"encoding/json"
5	"fmt"
6
7	"github.com/gophercloud/gophercloud"
8	"github.com/gophercloud/gophercloud/pagination"
9)
10
11// Topology represents a CPU Topology.
12type Topology struct {
13	Sockets int `json:"sockets"`
14	Cores   int `json:"cores"`
15	Threads int `json:"threads"`
16}
17
18// CPUInfo represents CPU information of the hypervisor.
19type CPUInfo struct {
20	Vendor   string   `json:"vendor"`
21	Arch     string   `json:"arch"`
22	Model    string   `json:"model"`
23	Features []string `json:"features"`
24	Topology Topology `json:"topology"`
25}
26
27// Service represents a Compute service running on the hypervisor.
28type Service struct {
29	Host           string `json:"host"`
30	ID             int    `json:"id"`
31	DisabledReason string `json:"disabled_reason"`
32}
33
34// Hypervisor represents a hypervisor in the OpenStack cloud.
35type Hypervisor struct {
36	// A structure that contains cpu information like arch, model, vendor,
37	// features and topology.
38	CPUInfo CPUInfo `json:"-"`
39
40	// The current_workload is the number of tasks the hypervisor is responsible
41	// for. This will be equal or greater than the number of active VMs on the
42	// system (it can be greater when VMs are being deleted and the hypervisor is
43	// still cleaning up).
44	CurrentWorkload int `json:"current_workload"`
45
46	// Status of the hypervisor, either "enabled" or "disabled".
47	Status string `json:"status"`
48
49	// State of the hypervisor, either "up" or "down".
50	State string `json:"state"`
51
52	// DiskAvailableLeast is the actual free disk on this hypervisor,
53	// measured in GB.
54	DiskAvailableLeast int `json:"disk_available_least"`
55
56	// HostIP is the hypervisor's IP address.
57	HostIP string `json:"host_ip"`
58
59	// FreeDiskGB is the free disk remaining on the hypervisor, measured in GB.
60	FreeDiskGB int `json:"-"`
61
62	// FreeRAMMB is the free RAM in the hypervisor, measured in MB.
63	FreeRamMB int `json:"free_ram_mb"`
64
65	// HypervisorHostname is the hostname of the hypervisor.
66	HypervisorHostname string `json:"hypervisor_hostname"`
67
68	// HypervisorType is the type of hypervisor.
69	HypervisorType string `json:"hypervisor_type"`
70
71	// HypervisorVersion is the version of the hypervisor.
72	HypervisorVersion int `json:"-"`
73
74	// ID is the unique ID of the hypervisor.
75	ID int `json:"id"`
76
77	// LocalGB is the disk space in the hypervisor, measured in GB.
78	LocalGB int `json:"-"`
79
80	// LocalGBUsed is the used disk space of the  hypervisor, measured in GB.
81	LocalGBUsed int `json:"local_gb_used"`
82
83	// MemoryMB is the total memory of the hypervisor, measured in MB.
84	MemoryMB int `json:"memory_mb"`
85
86	// MemoryMBUsed is the used memory of the hypervisor, measured in MB.
87	MemoryMBUsed int `json:"memory_mb_used"`
88
89	// RunningVMs is the The number of running vms on the hypervisor.
90	RunningVMs int `json:"running_vms"`
91
92	// Service is the service this hypervisor represents.
93	Service Service `json:"service"`
94
95	// VCPUs is the total number of vcpus on the hypervisor.
96	VCPUs int `json:"vcpus"`
97
98	// VCPUsUsed is the number of used vcpus on the hypervisor.
99	VCPUsUsed int `json:"vcpus_used"`
100}
101
102func (r *Hypervisor) UnmarshalJSON(b []byte) error {
103	type tmp Hypervisor
104	var s struct {
105		tmp
106		CPUInfo           interface{} `json:"cpu_info"`
107		HypervisorVersion interface{} `json:"hypervisor_version"`
108		FreeDiskGB        interface{} `json:"free_disk_gb"`
109		LocalGB           interface{} `json:"local_gb"`
110	}
111
112	err := json.Unmarshal(b, &s)
113	if err != nil {
114		return err
115	}
116
117	*r = Hypervisor(s.tmp)
118
119	// Newer versions return the CPU info as the correct type.
120	// Older versions return the CPU info as a string and need to be
121	// unmarshalled by the json parser.
122	var tmpb []byte
123
124	switch t := s.CPUInfo.(type) {
125	case string:
126		tmpb = []byte(t)
127	case map[string]interface{}:
128		tmpb, err = json.Marshal(t)
129		if err != nil {
130			return err
131		}
132	default:
133		return fmt.Errorf("CPUInfo has unexpected type: %T", t)
134	}
135
136	err = json.Unmarshal(tmpb, &r.CPUInfo)
137	if err != nil {
138		return err
139	}
140
141	// These fields may be returned as a scientific notation, so they need
142	// converted to int.
143	switch t := s.HypervisorVersion.(type) {
144	case int:
145		r.HypervisorVersion = t
146	case float64:
147		r.HypervisorVersion = int(t)
148	default:
149		return fmt.Errorf("Hypervisor version of unexpected type")
150	}
151
152	switch t := s.FreeDiskGB.(type) {
153	case int:
154		r.FreeDiskGB = t
155	case float64:
156		r.FreeDiskGB = int(t)
157	default:
158		return fmt.Errorf("Free disk GB of unexpected type")
159	}
160
161	switch t := s.LocalGB.(type) {
162	case int:
163		r.LocalGB = t
164	case float64:
165		r.LocalGB = int(t)
166	default:
167		return fmt.Errorf("Local GB of unexpected type")
168	}
169
170	return nil
171}
172
173// HypervisorPage represents a single page of all Hypervisors from a List
174// request.
175type HypervisorPage struct {
176	pagination.SinglePageBase
177}
178
179// IsEmpty determines whether or not a HypervisorPage is empty.
180func (page HypervisorPage) IsEmpty() (bool, error) {
181	va, err := ExtractHypervisors(page)
182	return len(va) == 0, err
183}
184
185// ExtractHypervisors interprets a page of results as a slice of Hypervisors.
186func ExtractHypervisors(p pagination.Page) ([]Hypervisor, error) {
187	var h struct {
188		Hypervisors []Hypervisor `json:"hypervisors"`
189	}
190	err := (p.(HypervisorPage)).ExtractInto(&h)
191	return h.Hypervisors, err
192}
193
194type HypervisorResult struct {
195	gophercloud.Result
196}
197
198// Extract interprets any HypervisorResult as a Hypervisor, if possible.
199func (r HypervisorResult) Extract() (*Hypervisor, error) {
200	var s struct {
201		Hypervisor Hypervisor `json:"hypervisor"`
202	}
203	err := r.ExtractInto(&s)
204	return &s.Hypervisor, err
205}
206
207// Statistics represents a summary statistics for all enabled
208// hypervisors over all compute nodes in the OpenStack cloud.
209type Statistics struct {
210	// The number of hypervisors.
211	Count int `json:"count"`
212
213	// The current_workload is the number of tasks the hypervisor is responsible for
214	CurrentWorkload int `json:"current_workload"`
215
216	// The actual free disk on this hypervisor(in GB).
217	DiskAvailableLeast int `json:"disk_available_least"`
218
219	// The free disk remaining on this hypervisor(in GB).
220	FreeDiskGB int `json:"free_disk_gb"`
221
222	// The free RAM in this hypervisor(in MB).
223	FreeRamMB int `json:"free_ram_mb"`
224
225	// The disk in this hypervisor(in GB).
226	LocalGB int `json:"local_gb"`
227
228	// The disk used in this hypervisor(in GB).
229	LocalGBUsed int `json:"local_gb_used"`
230
231	// The memory of this hypervisor(in MB).
232	MemoryMB int `json:"memory_mb"`
233
234	// The memory used in this hypervisor(in MB).
235	MemoryMBUsed int `json:"memory_mb_used"`
236
237	// The total number of running vms on all hypervisors.
238	RunningVMs int `json:"running_vms"`
239
240	// The number of vcpu in this hypervisor.
241	VCPUs int `json:"vcpus"`
242
243	// The number of vcpu used in this hypervisor.
244	VCPUsUsed int `json:"vcpus_used"`
245}
246
247type StatisticsResult struct {
248	gophercloud.Result
249}
250
251// Extract interprets any StatisticsResult as a Statistics, if possible.
252func (r StatisticsResult) Extract() (*Statistics, error) {
253	var s struct {
254		Stats Statistics `json:"hypervisor_statistics"`
255	}
256	err := r.ExtractInto(&s)
257	return &s.Stats, err
258}
259
260// Uptime represents uptime and additional info for a specific hypervisor.
261type Uptime struct {
262	// The hypervisor host name provided by the Nova virt driver.
263	// For the Ironic driver, it is the Ironic node uuid.
264	HypervisorHostname string `json:"hypervisor_hostname"`
265
266	// The id of the hypervisor.
267	ID int `json:"id"`
268
269	// The state of the hypervisor. One of up or down.
270	State string `json:"state"`
271
272	// The status of the hypervisor. One of enabled or disabled.
273	Status string `json:"status"`
274
275	// The total uptime of the hypervisor and information about average load.
276	Uptime string `json:"uptime"`
277}
278
279type UptimeResult struct {
280	gophercloud.Result
281}
282
283// Extract interprets any UptimeResult as a Uptime, if possible.
284func (r UptimeResult) Extract() (*Uptime, error) {
285	var s struct {
286		Uptime Uptime `json:"hypervisor"`
287	}
288	err := r.ExtractInto(&s)
289	return &s.Uptime, err
290}
291