master
go 413 lines 11.2 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package discover
4
5 import (
6 "time"
7
8 rs "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/vsphere/resources"
9
10 "github.com/vmware/govmomi/vim25/mo"
11 "github.com/vmware/govmomi/vim25/types"
12 )
13
14 func (d Discoverer) build(raw *resources) *rs.Resources {
15 d.Debug("discovering : building : starting building resources process")
16 t := time.Now()
17
18 var res rs.Resources
19 res.DataCenters = d.buildDatacenters(raw.dcs)
20 res.Folders = d.buildFolders(raw.folders)
21 res.Clusters = d.buildClusters(raw.clusters)
22 fixClustersParentID(&res)
23 res.Hosts = d.buildHosts(raw.hosts)
24 res.VMs = d.buildVMs(raw.vms)
25 res.Datastores = d.buildDatastores(raw.datastores)
26 res.Networks = d.buildNetworks(raw.networks)
27 res.StoragePods = d.buildStoragePods(raw.storagePods)
28 res.ResourcePools = d.buildResourcePools(raw.resourcePools, res.Clusters)
29
30 d.Infof("discovering : building : built %d/%d dcs, %d/%d folders, %d/%d clusters, %d/%d hosts, %d/%d vms, %d/%d datastores, %d/%d networks, %d/%d datastore clusters, %d/%d resource pools, process took %s",
31 len(res.DataCenters),
32 len(raw.dcs),
33 len(res.Folders),
34 len(raw.folders),
35 len(res.Clusters),
36 len(raw.clusters),
37 len(res.Hosts),
38 len(raw.hosts),
39 len(res.VMs),
40 len(raw.vms),
41 len(res.Datastores),
42 len(raw.datastores),
43 len(res.Networks),
44 len(raw.networks),
45 len(res.StoragePods),
46 len(raw.storagePods),
47 len(res.ResourcePools),
48 len(raw.resourcePools),
49 time.Since(t),
50 )
51 return &res
52 }
53
54 // cluster parent is folder by default
55 // should be called after buildDatacenters, buildFolders and buildClusters
56 func fixClustersParentID(res *rs.Resources) {
57 for _, c := range res.Clusters {
58 c.ParentID = findClusterDcID(c.ParentID, res.Folders)
59 }
60 }
61
62 func findClusterDcID(parentID string, folders rs.Folders) string {
63 return findFolderRootID(parentID, folders)
64 }
65
66 func (Discoverer) buildDatacenters(raw []mo.Datacenter) rs.DataCenters {
67 dcs := make(rs.DataCenters)
68 for _, d := range raw {
69 dcs.Put(newDC(d))
70 }
71 return dcs
72 }
73
74 func newDC(raw mo.Datacenter) *rs.Datacenter {
75 // Datacenter1 datacenter-2 group-h4 group-v3
76 return &rs.Datacenter{
77 Name: raw.Name,
78 ID: raw.Reference().Value,
79 }
80 }
81
82 func (Discoverer) buildFolders(raw []mo.Folder) rs.Folders {
83 fs := make(rs.Folders)
84 for _, d := range raw {
85 if f := newFolder(d); f != nil {
86 fs.Put(f)
87 }
88 }
89 return fs
90 }
91
92 func newFolder(raw mo.Folder) *rs.Folder {
93 parentID := parentRefValue(raw.Parent)
94 if parentID == "" {
95 return nil
96 }
97 // vm group-v55 datacenter-54
98 // host group-h56 datacenter-54
99 // datastore group-s57 datacenter-54
100 // network group-n58 datacenter-54
101 return &rs.Folder{
102 Name: raw.Name,
103 ID: raw.Reference().Value,
104 ParentID: parentID,
105 }
106 }
107
108 func (Discoverer) buildClusters(raw []mo.ComputeResource) rs.Clusters {
109 clusters := make(rs.Clusters)
110 for _, c := range raw {
111 if cluster := newCluster(c); cluster != nil {
112 clusters.Put(cluster)
113 }
114 }
115 return clusters
116 }
117
118 func newCluster(raw mo.ComputeResource) *rs.Cluster {
119 parentID := parentRefValue(raw.Parent)
120 if parentID == "" {
121 return nil
122 }
123 // s - dummy cluster, c - created by user cluster
124 // 192.168.0.201 domain-s61 group-h4
125 // New Cluster1 domain-c52 group-h67
126 cluster := &rs.Cluster{
127 Name: raw.Name,
128 ID: raw.Reference().Value,
129 ParentID: parentID,
130 CustomValues: customFieldValues(raw.CustomValue),
131 Ref: raw.Reference(),
132 }
133 rs.SetClusterVSANInfo(cluster, raw.ConfigurationEx)
134 return cluster
135 }
136
137 func (d Discoverer) buildHosts(raw []mo.HostSystem) rs.Hosts {
138 hosts := make(rs.Hosts)
139 for _, h := range raw {
140 if host := newHost(h); host != nil {
141 hosts.Put(host)
142 }
143 }
144 return hosts
145 }
146
147 func newHost(raw mo.HostSystem) *rs.Host {
148 parentID := parentRefValue(raw.Parent)
149 if parentID == "" {
150 return nil
151 }
152 // 192.168.0.201 host-22 domain-s61
153 // 192.168.0.202 host-28 domain-c52
154 // 192.168.0.203 host-33 domain-c52
155 host := &rs.Host{
156 Name: raw.Name,
157 ID: raw.Reference().Value,
158 ParentID: parentID,
159 CustomValues: customFieldValues(raw.CustomValue),
160 ConnectionState: string(raw.Runtime.ConnectionState),
161 PowerState: string(raw.Runtime.PowerState),
162 InMaintenanceMode: raw.Runtime.InMaintenanceMode,
163 OverallStatus: string(raw.Summary.OverallStatus),
164 Ref: raw.Reference(),
165 }
166 if raw.Config != nil && raw.Config.VsanHostConfig != nil && raw.Config.VsanHostConfig.ClusterInfo != nil {
167 host.VSANNodeUUID = raw.Config.VsanHostConfig.ClusterInfo.NodeUuid
168 }
169 return host
170 }
171
172 func (d Discoverer) buildVMs(raw []mo.VirtualMachine) rs.VMs {
173 vms := make(rs.VMs)
174 for _, v := range raw {
175 vms.Put(newVM(v))
176 }
177 return vms
178 }
179
180 func newVM(raw mo.VirtualMachine) *rs.VM {
181 // deb91 vm-25 group-v3 host-22
182 var hostID string
183 if raw.Runtime.Host != nil {
184 hostID = raw.Runtime.Host.Value
185 }
186 var folderID string
187 if raw.Parent != nil {
188 folderID = raw.Parent.Value
189 }
190 var toolsRunningStatus, toolsVersionStatus string
191 if raw.Summary.Guest != nil {
192 toolsRunningStatus = raw.Summary.Guest.ToolsRunningStatus
193 toolsVersionStatus = raw.Summary.Guest.ToolsVersionStatus2
194 }
195 var committed, uncommitted, unshared int64
196 if raw.Summary.Storage != nil {
197 committed = raw.Summary.Storage.Committed
198 uncommitted = raw.Summary.Storage.Uncommitted
199 unshared = raw.Summary.Storage.Unshared
200 }
201 var instanceUUID string
202 if raw.Config != nil {
203 instanceUUID = raw.Config.InstanceUuid
204 }
205 snapshot := summarizeSnapshotInfo(raw.Snapshot)
206 return &rs.VM{
207 Name: raw.Name,
208 ID: raw.Reference().Value,
209 ParentID: hostID,
210 FolderParentID: folderID,
211 CustomValues: customFieldValues(raw.CustomValue),
212 ConnectionState: string(raw.Runtime.ConnectionState),
213 PowerState: string(raw.Runtime.PowerState),
214 ToolsRunningStatus: toolsRunningStatus,
215 ToolsVersionStatus: toolsVersionStatus,
216 InstanceUUID: instanceUUID,
217 ConsolidationNeeded: raw.Runtime.ConsolidationNeeded,
218 ConfigCPU: int64(raw.Summary.Config.NumCpu),
219 ConfigMemory: int64(raw.Summary.Config.MemorySizeMB),
220 ConfigDisks: int64(raw.Summary.Config.NumVirtualDisks),
221 ConfigNICs: int64(raw.Summary.Config.NumEthernetCards),
222 StorageCommitted: committed,
223 StorageUncommitted: uncommitted,
224 StorageUnshared: unshared,
225 OverallStatus: string(raw.Summary.OverallStatus),
226 SnapshotCount: snapshot.count,
227 SnapshotMaxChainDepth: snapshot.maxChainDepth,
228 SnapshotOldestCreateTime: snapshot.oldestCreateTime,
229 Ref: raw.Reference(),
230 }
231 }
232
233 func (d Discoverer) buildDatastores(raw []mo.Datastore) rs.Datastores {
234 datastores := make(rs.Datastores)
235 for _, ds := range raw {
236 if datastore := newDatastore(ds); datastore != nil {
237 datastores.Put(datastore)
238 }
239 }
240 return datastores
241 }
242
243 func newDatastore(raw mo.Datastore) *rs.Datastore {
244 parentID := parentRefValue(raw.Parent)
245 if parentID == "" {
246 return nil
247 }
248 return &rs.Datastore{
249 Name: raw.Name,
250 ID: raw.Reference().Value,
251 ParentID: parentID,
252 CustomValues: customFieldValues(raw.CustomValue),
253 OverallStatus: string(raw.OverallStatus),
254 Type: raw.Summary.Type,
255 Capacity: raw.Summary.Capacity,
256 FreeSpace: raw.Summary.FreeSpace,
257 Uncommitted: raw.Summary.Uncommitted,
258 Accessible: raw.Summary.Accessible,
259 MaintenanceMode: raw.Summary.MaintenanceMode,
260 MultipleHostAccess: raw.Summary.MultipleHostAccess,
261 Ref: raw.Reference(),
262 }
263 }
264
265 func (d Discoverer) buildNetworks(raw []mo.Network) rs.Networks {
266 networks := make(rs.Networks)
267 for _, network := range raw {
268 networks.Put(newNetwork(network))
269 }
270 return networks
271 }
272
273 func newNetwork(raw mo.Network) *rs.Network {
274 var accessible bool
275 var ipPoolName string
276 if raw.Summary != nil {
277 if summary := raw.Summary.GetNetworkSummary(); summary != nil {
278 accessible = summary.Accessible
279 ipPoolName = summary.IpPoolName
280 }
281 }
282
283 networkType := raw.Reference().Type
284 if networkType == "" {
285 networkType = "Network"
286 }
287
288 var parentID string
289 if raw.Parent != nil {
290 parentID = raw.Parent.Value
291 }
292
293 return &rs.Network{
294 Name: raw.Name,
295 ID: raw.Reference().Value,
296 Type: networkType,
297 ParentID: parentID,
298 CustomValues: customFieldValues(raw.CustomValue),
299 Accessible: accessible,
300 IPPoolName: ipPoolName,
301 HostIDs: refValues(raw.Host),
302 VMIDs: refValues(raw.Vm),
303 OverallStatus: string(raw.OverallStatus),
304 Ref: raw.Reference(),
305 }
306 }
307
308 func refValues(refs []types.ManagedObjectReference) []string {
309 if len(refs) == 0 {
310 return nil
311 }
312 values := make([]string, 0, len(refs))
313 for _, ref := range refs {
314 if ref.Value != "" {
315 values = append(values, ref.Value)
316 }
317 }
318 return values
319 }
320
321 func (d Discoverer) buildStoragePods(raw []mo.StoragePod) rs.StoragePods {
322 pods := make(rs.StoragePods)
323 for _, pod := range raw {
324 if storagePod := newStoragePod(pod); storagePod != nil {
325 pods.Put(storagePod)
326 }
327 }
328 return pods
329 }
330
331 func newStoragePod(raw mo.StoragePod) *rs.StoragePod {
332 parentID := parentRefValue(raw.Parent)
333 if parentID == "" {
334 return nil
335 }
336 var capacity, freeSpace int64
337 if raw.Summary != nil {
338 capacity = raw.Summary.Capacity
339 freeSpace = raw.Summary.FreeSpace
340 }
341 var storageDRSEnabled *bool
342 if raw.PodStorageDrsEntry != nil {
343 storageDRSEnabled = new(raw.PodStorageDrsEntry.StorageDrsConfig.PodConfig.Enabled)
344 }
345 return &rs.StoragePod{
346 Name: raw.Name,
347 ID: raw.Reference().Value,
348 ParentID: parentID,
349 CustomValues: customFieldValues(raw.CustomValue),
350 Capacity: capacity,
351 FreeSpace: freeSpace,
352 StorageDRSEnabled: storageDRSEnabled,
353 OverallStatus: string(raw.OverallStatus),
354 Ref: raw.Reference(),
355 }
356 }
357
358 func (d Discoverer) buildResourcePools(raw []mo.ResourcePool, clusters rs.Clusters) rs.ResourcePools {
359 pools := make(rs.ResourcePools)
360 for _, rp := range raw {
361 // owner is the cluster that owns this pool
362 ownerID := rp.Owner.Value
363 if ownerID == "" {
364 continue
365 }
366 // skip pools whose owner is a dummy cluster (standalone host)
367 if isDummyCluster(ownerID) {
368 continue
369 }
370 // skip pools whose owner cluster wasn't discovered
371 if clusters.Get(ownerID) == nil {
372 continue
373 }
374 pools.Put(newResourcePool(rp))
375 }
376 return pools
377 }
378
379 func newResourcePool(raw mo.ResourcePool) *rs.ResourcePool {
380 return &rs.ResourcePool{
381 Name: raw.Name,
382 ID: raw.Reference().Value,
383 ParentID: raw.Owner.Value, // owner cluster ref
384 CustomValues: customFieldValues(raw.CustomValue),
385 Ref: raw.Reference(),
386 }
387 }
388
389 func customFieldValues(values []types.BaseCustomFieldValue) map[int32]string {
390 if len(values) == 0 {
391 return nil
392 }
393
394 out := make(map[int32]string, len(values))
395 for _, value := range values {
396 stringValue, ok := value.(*types.CustomFieldStringValue)
397 if !ok || stringValue == nil || stringValue.Value == "" {
398 continue
399 }
400 out[stringValue.Key] = stringValue.Value
401 }
402 if len(out) == 0 {
403 return nil
404 }
405 return out
406 }
407
408 func parentRefValue(ref *types.ManagedObjectReference) string {
409 if ref == nil {
410 return ""
411 }
412 return ref.Value
413 }