github.com/netdata/go.d.plugin@v0.58.1/modules/vsphere/charts.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package vsphere 4 5 import ( 6 "fmt" 7 "strings" 8 9 "github.com/netdata/go.d.plugin/agent/module" 10 rs "github.com/netdata/go.d.plugin/modules/vsphere/resources" 11 ) 12 13 const ( 14 prioVMCPUUtilization = module.Priority + iota 15 prioVmMemoryUtilization 16 prioVmMemoryUsage 17 prioVmMemorySwapUsage 18 prioVmMemorySwapIO 19 prioVmDiskIO 20 prioVmDiskMaxLatency 21 prioVmNetworkTraffic 22 prioVmNetworkPackets 23 prioVmNetworkDrops 24 prioVmOverallStatus 25 prioVmSystemUptime 26 27 prioHostCPUUtilization 28 prioHostMemoryUtilization 29 prioHostMemoryUsage 30 prioHostMemorySwapIO 31 prioHostDiskIO 32 prioHostDiskMaxLatency 33 prioHostNetworkTraffic 34 prioHostNetworkPackets 35 prioHostNetworkDrops 36 prioHostNetworkErrors 37 prioHostOverallStatus 38 prioHostSystemUptime 39 ) 40 41 var ( 42 vmChartsTmpl = module.Charts{ 43 vmCPUUtilizationChartTmpl.Copy(), 44 45 vmMemoryUtilizationChartTmpl.Copy(), 46 vmMemoryUsageChartTmpl.Copy(), 47 vmMemorySwapUsageChartTmpl.Copy(), 48 vmMemorySwapIOChartTmpl.Copy(), 49 50 vmDiskIOChartTmpl.Copy(), 51 vmDiskMaxLatencyChartTmpl.Copy(), 52 53 vmNetworkTrafficChartTmpl.Copy(), 54 vmNetworkPacketsChartTmpl.Copy(), 55 vmNetworkDropsChartTmpl.Copy(), 56 57 vmOverallStatusChartTmpl.Copy(), 58 59 vmSystemUptimeChartTmpl.Copy(), 60 } 61 62 vmCPUUtilizationChartTmpl = module.Chart{ 63 ID: "%s_cpu_utilization", 64 Title: "Virtual Machine CPU utilization", 65 Units: "percentage", 66 Fam: "vms cpu", 67 Ctx: "vsphere.vm_cpu_utilization", 68 Priority: prioVMCPUUtilization, 69 Dims: module.Dims{ 70 {ID: "%s_cpu.usage.average", Name: "used", Div: 100}, 71 }, 72 } 73 74 // Ref: https://www.vmware.com/support/developer/converter-sdk/conv51_apireference/memory_counters.html 75 vmMemoryUtilizationChartTmpl = module.Chart{ 76 ID: "%s_mem_utilization", 77 Title: "Virtual Machine memory utilization", 78 Units: "percentage", 79 Fam: "vms mem", 80 Ctx: "vsphere.vm_mem_utilization", 81 Priority: prioVmMemoryUtilization, 82 Dims: module.Dims{ 83 {ID: "%s_mem.usage.average", Name: "used", Div: 100}, 84 }, 85 } 86 vmMemoryUsageChartTmpl = module.Chart{ 87 ID: "%s_mem_usage", 88 Title: "Virtual Machine memory usage", 89 Units: "KiB", 90 Fam: "vms mem", 91 Ctx: "vsphere.vm_mem_usage", 92 Priority: prioVmMemoryUsage, 93 Dims: module.Dims{ 94 {ID: "%s_mem.granted.average", Name: "granted"}, 95 {ID: "%s_mem.consumed.average", Name: "consumed"}, 96 {ID: "%s_mem.active.average", Name: "active"}, 97 {ID: "%s_mem.shared.average", Name: "shared"}, 98 }, 99 } 100 vmMemorySwapUsageChartTmpl = module.Chart{ 101 ID: "%s_mem_swap_usage", 102 Title: "Virtual Machine VMKernel memory swap usage", 103 Units: "KiB", 104 Fam: "vms mem", 105 Ctx: "vsphere.vm_mem_swap_usage", 106 Priority: prioVmMemorySwapUsage, 107 Dims: module.Dims{ 108 {ID: "%s_mem.swapped.average", Name: "swapped"}, 109 }, 110 } 111 vmMemorySwapIOChartTmpl = module.Chart{ 112 ID: "%s_mem_swap_io_rate", 113 Title: "Virtual Machine VMKernel memory swap IO", 114 Units: "KiB/s", 115 Fam: "vms mem", 116 Ctx: "vsphere.vm_mem_swap_io", 117 Type: module.Area, 118 Priority: prioVmMemorySwapIO, 119 Dims: module.Dims{ 120 {ID: "%s_mem.swapinRate.average", Name: "in"}, 121 {ID: "%s_mem.swapoutRate.average", Name: "out"}, 122 }, 123 } 124 125 vmDiskIOChartTmpl = module.Chart{ 126 ID: "%s_disk_io", 127 Title: "Virtual Machine disk IO", 128 Units: "KiB/s", 129 Fam: "vms disk", 130 Ctx: "vsphere.vm_disk_io", 131 Type: module.Area, 132 Priority: prioVmDiskIO, 133 Dims: module.Dims{ 134 {ID: "%s_disk.read.average", Name: "read"}, 135 {ID: "%s_disk.write.average", Name: "write", Mul: -1}, 136 }, 137 } 138 vmDiskMaxLatencyChartTmpl = module.Chart{ 139 ID: "%s_disk_max_latency", 140 Title: "Virtual Machine disk max latency", 141 Units: "milliseconds", 142 Fam: "vms disk", 143 Ctx: "vsphere.vm_disk_max_latency", 144 Priority: prioVmDiskMaxLatency, 145 Dims: module.Dims{ 146 {ID: "%s_disk.maxTotalLatency.latest", Name: "latency"}, 147 }, 148 } 149 150 vmNetworkTrafficChartTmpl = module.Chart{ 151 ID: "%s_net_traffic", 152 Title: "Virtual Machine network traffic", 153 Units: "KiB/s", 154 Fam: "vms net", 155 Ctx: "vsphere.vm_net_traffic", 156 Type: module.Area, 157 Priority: prioVmNetworkTraffic, 158 Dims: module.Dims{ 159 {ID: "%s_net.bytesRx.average", Name: "received"}, 160 {ID: "%s_net.bytesTx.average", Name: "sent", Mul: -1}, 161 }, 162 } 163 vmNetworkPacketsChartTmpl = module.Chart{ 164 ID: "%s_net_packets", 165 Title: "Virtual Machine network packets", 166 Units: "packets", 167 Fam: "vms net", 168 Ctx: "vsphere.vm_net_packets", 169 Priority: prioVmNetworkPackets, 170 Dims: module.Dims{ 171 {ID: "%s_net.packetsRx.summation", Name: "received"}, 172 {ID: "%s_net.packetsTx.summation", Name: "sent", Mul: -1}, 173 }, 174 } 175 vmNetworkDropsChartTmpl = module.Chart{ 176 ID: "%s_net_drops", 177 Title: "Virtual Machine network dropped packets", 178 Units: "drops", 179 Fam: "vms net", 180 Ctx: "vsphere.vm_net_drops", 181 Priority: prioVmNetworkDrops, 182 Dims: module.Dims{ 183 {ID: "%s_net.droppedRx.summation", Name: "received"}, 184 {ID: "%s_net.droppedTx.summation", Name: "sent", Mul: -1}, 185 }, 186 } 187 188 vmOverallStatusChartTmpl = module.Chart{ 189 ID: "%s_overall_status", 190 Title: "Virtual Machine overall alarm status", 191 Units: "status", 192 Fam: "vms status", 193 Ctx: "vsphere.vm_overall_status", 194 Priority: prioVmOverallStatus, 195 Dims: module.Dims{ 196 {ID: "%s_overall.status.green", Name: "green"}, 197 {ID: "%s_overall.status.red", Name: "red"}, 198 {ID: "%s_overall.status.yellow", Name: "yellow"}, 199 {ID: "%s_overall.status.gray", Name: "gray"}, 200 }, 201 } 202 203 vmSystemUptimeChartTmpl = module.Chart{ 204 ID: "%s_system_uptime", 205 Title: "Virtual Machine system uptime", 206 Units: "seconds", 207 Fam: "vms uptime", 208 Ctx: "vsphere.vm_system_uptime", 209 Priority: prioVmSystemUptime, 210 Dims: module.Dims{ 211 {ID: "%s_sys.uptime.latest", Name: "uptime"}, 212 }, 213 } 214 ) 215 216 var ( 217 hostChartsTmpl = module.Charts{ 218 hostCPUUtilizationChartTmpl.Copy(), 219 220 hostMemUtilizationChartTmpl.Copy(), 221 hostMemUsageChartTmpl.Copy(), 222 hostMemSwapIOChartTmpl.Copy(), 223 224 hostDiskIOChartTmpl.Copy(), 225 hostDiskMaxLatencyChartTmpl.Copy(), 226 227 hostNetworkTraffic.Copy(), 228 hostNetworkPacketsChartTmpl.Copy(), 229 hostNetworkDropsChartTmpl.Copy(), 230 hostNetworkErrorsChartTmpl.Copy(), 231 232 hostOverallStatusChartTmpl.Copy(), 233 234 hostSystemUptimeChartTmpl.Copy(), 235 } 236 hostCPUUtilizationChartTmpl = module.Chart{ 237 ID: "%s_cpu_usage_total", 238 Title: "ESXi Host CPU utilization", 239 Units: "percentage", 240 Fam: "hosts cpu", 241 Ctx: "vsphere.host_cpu_utilization", 242 Priority: prioHostCPUUtilization, 243 Dims: module.Dims{ 244 {ID: "%s_cpu.usage.average", Name: "used", Div: 100}, 245 }, 246 } 247 hostMemUtilizationChartTmpl = module.Chart{ 248 ID: "%s_mem_utilization", 249 Title: "ESXi Host memory utilization", 250 Units: "percentage", 251 Fam: "hosts mem", 252 Ctx: "vsphere.host_mem_utilization", 253 Priority: prioHostMemoryUtilization, 254 Dims: module.Dims{ 255 {ID: "%s_mem.usage.average", Name: "used", Div: 100}, 256 }, 257 } 258 hostMemUsageChartTmpl = module.Chart{ 259 ID: "%s_mem_usage", 260 Title: "ESXi Host memory usage", 261 Units: "KiB", 262 Fam: "hosts mem", 263 Ctx: "vsphere.host_mem_usage", 264 Priority: prioHostMemoryUsage, 265 Dims: module.Dims{ 266 {ID: "%s_mem.granted.average", Name: "granted"}, 267 {ID: "%s_mem.consumed.average", Name: "consumed"}, 268 {ID: "%s_mem.active.average", Name: "active"}, 269 {ID: "%s_mem.shared.average", Name: "shared"}, 270 {ID: "%s_mem.sharedcommon.average", Name: "sharedcommon"}, 271 }, 272 } 273 hostMemSwapIOChartTmpl = module.Chart{ 274 ID: "%s_mem_swap_rate", 275 Title: "ESXi Host VMKernel memory swap IO", 276 Units: "KiB/s", 277 Fam: "hosts mem", 278 Ctx: "vsphere.host_mem_swap_io", 279 Type: module.Area, 280 Priority: prioHostMemorySwapIO, 281 Dims: module.Dims{ 282 {ID: "%s_mem.swapinRate.average", Name: "in"}, 283 {ID: "%s_mem.swapoutRate.average", Name: "out"}, 284 }, 285 } 286 287 hostDiskIOChartTmpl = module.Chart{ 288 ID: "%s_disk_io", 289 Title: "ESXi Host disk IO", 290 Units: "KiB/s", 291 Fam: "hosts disk", 292 Ctx: "vsphere.host_disk_io", 293 Type: module.Area, 294 Priority: prioHostDiskIO, 295 Dims: module.Dims{ 296 {ID: "%s_disk.read.average", Name: "read"}, 297 {ID: "%s_disk.write.average", Name: "write", Mul: -1}, 298 }, 299 } 300 hostDiskMaxLatencyChartTmpl = module.Chart{ 301 ID: "%s_disk_max_latency", 302 Title: "ESXi Host disk max latency", 303 Units: "milliseconds", 304 Fam: "hosts disk", 305 Ctx: "vsphere.host_disk_max_latency", 306 Priority: prioHostDiskMaxLatency, 307 Dims: module.Dims{ 308 {ID: "%s_disk.maxTotalLatency.latest", Name: "latency"}, 309 }, 310 } 311 312 hostNetworkTraffic = module.Chart{ 313 ID: "%s_net_traffic", 314 Title: "ESXi Host network traffic", 315 Units: "KiB/s", 316 Fam: "hosts net", 317 Ctx: "vsphere.host_net_traffic", 318 Type: module.Area, 319 Priority: prioHostNetworkTraffic, 320 Dims: module.Dims{ 321 {ID: "%s_net.bytesRx.average", Name: "received"}, 322 {ID: "%s_net.bytesTx.average", Name: "sent", Mul: -1}, 323 }, 324 } 325 hostNetworkPacketsChartTmpl = module.Chart{ 326 ID: "%s_net_packets", 327 Title: "ESXi Host network packets", 328 Units: "packets", 329 Fam: "hosts net", 330 Ctx: "vsphere.host_net_packets", 331 Priority: prioHostNetworkPackets, 332 Dims: module.Dims{ 333 {ID: "%s_net.packetsRx.summation", Name: "received"}, 334 {ID: "%s_net.packetsTx.summation", Name: "sent", Mul: -1}, 335 }, 336 } 337 hostNetworkDropsChartTmpl = module.Chart{ 338 ID: "%s_net_drops_total", 339 Title: "ESXi Host network drops", 340 Units: "drops", 341 Fam: "hosts net", 342 Ctx: "vsphere.host_net_drops", 343 Priority: prioHostNetworkDrops, 344 Dims: module.Dims{ 345 {ID: "%s_net.droppedRx.summation", Name: "received"}, 346 {ID: "%s_net.droppedTx.summation", Name: "sent", Mul: -1}, 347 }, 348 } 349 hostNetworkErrorsChartTmpl = module.Chart{ 350 ID: "%s_net_errors", 351 Title: "ESXi Host network errors", 352 Units: "errors", 353 Fam: "hosts net", 354 Ctx: "vsphere.host_net_errors", 355 Priority: prioHostNetworkErrors, 356 Dims: module.Dims{ 357 {ID: "%s_net.errorsRx.summation", Name: "received"}, 358 {ID: "%s_net.errorsTx.summation", Name: "sent", Mul: -1}, 359 }, 360 } 361 362 hostOverallStatusChartTmpl = module.Chart{ 363 ID: "%s_overall_status", 364 Title: "ESXi Host overall alarm status", 365 Units: "status", 366 Fam: "hosts status", 367 Ctx: "vsphere.host_overall_status", 368 Priority: prioHostOverallStatus, 369 Dims: module.Dims{ 370 {ID: "%s_overall.status.green", Name: "green"}, 371 {ID: "%s_overall.status.red", Name: "red"}, 372 {ID: "%s_overall.status.yellow", Name: "yellow"}, 373 {ID: "%s_overall.status.gray", Name: "gray"}, 374 }, 375 } 376 hostSystemUptimeChartTmpl = module.Chart{ 377 ID: "%s_system_uptime", 378 Title: "ESXi Host system uptime", 379 Units: "seconds", 380 Fam: "hosts uptime", 381 Ctx: "vsphere.host_system_uptime", 382 Priority: prioHostSystemUptime, 383 Dims: module.Dims{ 384 {ID: "%s_sys.uptime.latest", Name: "uptime"}, 385 }, 386 } 387 ) 388 389 const failedUpdatesLimit = 10 390 391 func (vs *VSphere) updateCharts() { 392 for id, fails := range vs.discoveredHosts { 393 if fails >= failedUpdatesLimit { 394 vs.removeFromCharts(id) 395 delete(vs.charted, id) 396 delete(vs.discoveredHosts, id) 397 continue 398 } 399 400 host := vs.resources.Hosts.Get(id) 401 if host == nil || vs.charted[id] || fails != 0 { 402 continue 403 } 404 405 vs.charted[id] = true 406 charts := newHostCharts(host) 407 if err := vs.Charts().Add(*charts...); err != nil { 408 vs.Error(err) 409 } 410 } 411 412 for id, fails := range vs.discoveredVMs { 413 if fails >= failedUpdatesLimit { 414 vs.removeFromCharts(id) 415 delete(vs.charted, id) 416 delete(vs.discoveredVMs, id) 417 continue 418 } 419 420 vm := vs.resources.VMs.Get(id) 421 if vm == nil || vs.charted[id] || fails != 0 { 422 continue 423 } 424 425 vs.charted[id] = true 426 charts := newVMCHarts(vm) 427 if err := vs.Charts().Add(*charts...); err != nil { 428 vs.Error(err) 429 } 430 } 431 } 432 433 func newVMCHarts(vm *rs.VM) *module.Charts { 434 charts := vmChartsTmpl.Copy() 435 436 for _, chart := range *charts { 437 chart.ID = fmt.Sprintf(chart.ID, vm.ID) 438 chart.Labels = []module.Label{ 439 {Key: "datacenter", Value: vm.Hier.DC.Name}, 440 {Key: "cluster", Value: getVMClusterName(vm)}, 441 {Key: "host", Value: vm.Hier.Host.Name}, 442 {Key: "vm", Value: vm.Name}, 443 } 444 for _, dim := range chart.Dims { 445 dim.ID = fmt.Sprintf(dim.ID, vm.ID) 446 } 447 } 448 449 return charts 450 } 451 452 func getVMClusterName(vm *rs.VM) string { 453 if vm.Hier.Cluster.Name == vm.Hier.Host.Name { 454 return "" 455 } 456 return vm.Hier.Cluster.Name 457 } 458 459 func newHostCharts(host *rs.Host) *module.Charts { 460 charts := hostChartsTmpl.Copy() 461 462 for _, chart := range *charts { 463 chart.ID = fmt.Sprintf(chart.ID, host.ID) 464 chart.Labels = []module.Label{ 465 {Key: "datacenter", Value: host.Hier.DC.Name}, 466 {Key: "cluster", Value: getHostClusterName(host)}, 467 {Key: "host", Value: host.Name}, 468 } 469 470 for _, dim := range chart.Dims { 471 dim.ID = fmt.Sprintf(dim.ID, host.ID) 472 } 473 } 474 475 return charts 476 } 477 478 func getHostClusterName(host *rs.Host) string { 479 if host.Hier.Cluster.Name == host.Name { 480 return "" 481 } 482 return host.Hier.Cluster.Name 483 } 484 485 func (vs *VSphere) removeFromCharts(prefix string) { 486 for _, c := range *vs.Charts() { 487 if strings.HasPrefix(c.ID, prefix) { 488 c.MarkRemove() 489 c.MarkNotCreated() 490 } 491 } 492 } 493 494 //func findMetricSeriesByPrefix(ms []performance.MetricSeries, prefix string) []performance.MetricSeries { 495 // from := sort.Search(len(ms), func(i int) bool { return ms[i].Name >= prefix }) 496 // 497 // if from == len(ms) || !strings.HasPrefix(ms[from].Name, prefix) { 498 // return nil 499 // } 500 // 501 // until := from + 1 502 // for until < len(ms) && strings.HasPrefix(ms[until].Name, prefix) { 503 // until++ 504 // } 505 // return ms[from:until] 506 //}