diff options
Diffstat (limited to '')
-rw-r--r-- | src/go/collectors/go.d.plugin/modules/vsphere/charts.go | 506 |
1 files changed, 506 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/vsphere/charts.go b/src/go/collectors/go.d.plugin/modules/vsphere/charts.go new file mode 100644 index 000000000..ed4db941d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/vsphere/charts.go @@ -0,0 +1,506 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package vsphere + +import ( + "fmt" + "strings" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + rs "github.com/netdata/netdata/go/go.d.plugin/modules/vsphere/resources" +) + +const ( + prioVMCPUUtilization = module.Priority + iota + prioVmMemoryUtilization + prioVmMemoryUsage + prioVmMemorySwapUsage + prioVmMemorySwapIO + prioVmDiskIO + prioVmDiskMaxLatency + prioVmNetworkTraffic + prioVmNetworkPackets + prioVmNetworkDrops + prioVmOverallStatus + prioVmSystemUptime + + prioHostCPUUtilization + prioHostMemoryUtilization + prioHostMemoryUsage + prioHostMemorySwapIO + prioHostDiskIO + prioHostDiskMaxLatency + prioHostNetworkTraffic + prioHostNetworkPackets + prioHostNetworkDrops + prioHostNetworkErrors + prioHostOverallStatus + prioHostSystemUptime +) + +var ( + vmChartsTmpl = module.Charts{ + vmCPUUtilizationChartTmpl.Copy(), + + vmMemoryUtilizationChartTmpl.Copy(), + vmMemoryUsageChartTmpl.Copy(), + vmMemorySwapUsageChartTmpl.Copy(), + vmMemorySwapIOChartTmpl.Copy(), + + vmDiskIOChartTmpl.Copy(), + vmDiskMaxLatencyChartTmpl.Copy(), + + vmNetworkTrafficChartTmpl.Copy(), + vmNetworkPacketsChartTmpl.Copy(), + vmNetworkDropsChartTmpl.Copy(), + + vmOverallStatusChartTmpl.Copy(), + + vmSystemUptimeChartTmpl.Copy(), + } + + vmCPUUtilizationChartTmpl = module.Chart{ + ID: "%s_cpu_utilization", + Title: "Virtual Machine CPU utilization", + Units: "percentage", + Fam: "vms cpu", + Ctx: "vsphere.vm_cpu_utilization", + Priority: prioVMCPUUtilization, + Dims: module.Dims{ + {ID: "%s_cpu.usage.average", Name: "used", Div: 100}, + }, + } + + // Ref: https://www.vmware.com/support/developer/converter-sdk/conv51_apireference/memory_counters.html + vmMemoryUtilizationChartTmpl = module.Chart{ + ID: "%s_mem_utilization", + Title: "Virtual Machine memory utilization", + Units: "percentage", + Fam: "vms mem", + Ctx: "vsphere.vm_mem_utilization", + Priority: prioVmMemoryUtilization, + Dims: module.Dims{ + {ID: "%s_mem.usage.average", Name: "used", Div: 100}, + }, + } + vmMemoryUsageChartTmpl = module.Chart{ + ID: "%s_mem_usage", + Title: "Virtual Machine memory usage", + Units: "KiB", + Fam: "vms mem", + Ctx: "vsphere.vm_mem_usage", + Priority: prioVmMemoryUsage, + Dims: module.Dims{ + {ID: "%s_mem.granted.average", Name: "granted"}, + {ID: "%s_mem.consumed.average", Name: "consumed"}, + {ID: "%s_mem.active.average", Name: "active"}, + {ID: "%s_mem.shared.average", Name: "shared"}, + }, + } + vmMemorySwapUsageChartTmpl = module.Chart{ + ID: "%s_mem_swap_usage", + Title: "Virtual Machine VMKernel memory swap usage", + Units: "KiB", + Fam: "vms mem", + Ctx: "vsphere.vm_mem_swap_usage", + Priority: prioVmMemorySwapUsage, + Dims: module.Dims{ + {ID: "%s_mem.swapped.average", Name: "swapped"}, + }, + } + vmMemorySwapIOChartTmpl = module.Chart{ + ID: "%s_mem_swap_io_rate", + Title: "Virtual Machine VMKernel memory swap IO", + Units: "KiB/s", + Fam: "vms mem", + Ctx: "vsphere.vm_mem_swap_io", + Type: module.Area, + Priority: prioVmMemorySwapIO, + Dims: module.Dims{ + {ID: "%s_mem.swapinRate.average", Name: "in"}, + {ID: "%s_mem.swapoutRate.average", Name: "out"}, + }, + } + + vmDiskIOChartTmpl = module.Chart{ + ID: "%s_disk_io", + Title: "Virtual Machine disk IO", + Units: "KiB/s", + Fam: "vms disk", + Ctx: "vsphere.vm_disk_io", + Type: module.Area, + Priority: prioVmDiskIO, + Dims: module.Dims{ + {ID: "%s_disk.read.average", Name: "read"}, + {ID: "%s_disk.write.average", Name: "write", Mul: -1}, + }, + } + vmDiskMaxLatencyChartTmpl = module.Chart{ + ID: "%s_disk_max_latency", + Title: "Virtual Machine disk max latency", + Units: "milliseconds", + Fam: "vms disk", + Ctx: "vsphere.vm_disk_max_latency", + Priority: prioVmDiskMaxLatency, + Dims: module.Dims{ + {ID: "%s_disk.maxTotalLatency.latest", Name: "latency"}, + }, + } + + vmNetworkTrafficChartTmpl = module.Chart{ + ID: "%s_net_traffic", + Title: "Virtual Machine network traffic", + Units: "KiB/s", + Fam: "vms net", + Ctx: "vsphere.vm_net_traffic", + Type: module.Area, + Priority: prioVmNetworkTraffic, + Dims: module.Dims{ + {ID: "%s_net.bytesRx.average", Name: "received"}, + {ID: "%s_net.bytesTx.average", Name: "sent", Mul: -1}, + }, + } + vmNetworkPacketsChartTmpl = module.Chart{ + ID: "%s_net_packets", + Title: "Virtual Machine network packets", + Units: "packets", + Fam: "vms net", + Ctx: "vsphere.vm_net_packets", + Priority: prioVmNetworkPackets, + Dims: module.Dims{ + {ID: "%s_net.packetsRx.summation", Name: "received"}, + {ID: "%s_net.packetsTx.summation", Name: "sent", Mul: -1}, + }, + } + vmNetworkDropsChartTmpl = module.Chart{ + ID: "%s_net_drops", + Title: "Virtual Machine network dropped packets", + Units: "drops", + Fam: "vms net", + Ctx: "vsphere.vm_net_drops", + Priority: prioVmNetworkDrops, + Dims: module.Dims{ + {ID: "%s_net.droppedRx.summation", Name: "received"}, + {ID: "%s_net.droppedTx.summation", Name: "sent", Mul: -1}, + }, + } + + vmOverallStatusChartTmpl = module.Chart{ + ID: "%s_overall_status", + Title: "Virtual Machine overall alarm status", + Units: "status", + Fam: "vms status", + Ctx: "vsphere.vm_overall_status", + Priority: prioVmOverallStatus, + Dims: module.Dims{ + {ID: "%s_overall.status.green", Name: "green"}, + {ID: "%s_overall.status.red", Name: "red"}, + {ID: "%s_overall.status.yellow", Name: "yellow"}, + {ID: "%s_overall.status.gray", Name: "gray"}, + }, + } + + vmSystemUptimeChartTmpl = module.Chart{ + ID: "%s_system_uptime", + Title: "Virtual Machine system uptime", + Units: "seconds", + Fam: "vms uptime", + Ctx: "vsphere.vm_system_uptime", + Priority: prioVmSystemUptime, + Dims: module.Dims{ + {ID: "%s_sys.uptime.latest", Name: "uptime"}, + }, + } +) + +var ( + hostChartsTmpl = module.Charts{ + hostCPUUtilizationChartTmpl.Copy(), + + hostMemUtilizationChartTmpl.Copy(), + hostMemUsageChartTmpl.Copy(), + hostMemSwapIOChartTmpl.Copy(), + + hostDiskIOChartTmpl.Copy(), + hostDiskMaxLatencyChartTmpl.Copy(), + + hostNetworkTraffic.Copy(), + hostNetworkPacketsChartTmpl.Copy(), + hostNetworkDropsChartTmpl.Copy(), + hostNetworkErrorsChartTmpl.Copy(), + + hostOverallStatusChartTmpl.Copy(), + + hostSystemUptimeChartTmpl.Copy(), + } + hostCPUUtilizationChartTmpl = module.Chart{ + ID: "%s_cpu_usage_total", + Title: "ESXi Host CPU utilization", + Units: "percentage", + Fam: "hosts cpu", + Ctx: "vsphere.host_cpu_utilization", + Priority: prioHostCPUUtilization, + Dims: module.Dims{ + {ID: "%s_cpu.usage.average", Name: "used", Div: 100}, + }, + } + hostMemUtilizationChartTmpl = module.Chart{ + ID: "%s_mem_utilization", + Title: "ESXi Host memory utilization", + Units: "percentage", + Fam: "hosts mem", + Ctx: "vsphere.host_mem_utilization", + Priority: prioHostMemoryUtilization, + Dims: module.Dims{ + {ID: "%s_mem.usage.average", Name: "used", Div: 100}, + }, + } + hostMemUsageChartTmpl = module.Chart{ + ID: "%s_mem_usage", + Title: "ESXi Host memory usage", + Units: "KiB", + Fam: "hosts mem", + Ctx: "vsphere.host_mem_usage", + Priority: prioHostMemoryUsage, + Dims: module.Dims{ + {ID: "%s_mem.granted.average", Name: "granted"}, + {ID: "%s_mem.consumed.average", Name: "consumed"}, + {ID: "%s_mem.active.average", Name: "active"}, + {ID: "%s_mem.shared.average", Name: "shared"}, + {ID: "%s_mem.sharedcommon.average", Name: "sharedcommon"}, + }, + } + hostMemSwapIOChartTmpl = module.Chart{ + ID: "%s_mem_swap_rate", + Title: "ESXi Host VMKernel memory swap IO", + Units: "KiB/s", + Fam: "hosts mem", + Ctx: "vsphere.host_mem_swap_io", + Type: module.Area, + Priority: prioHostMemorySwapIO, + Dims: module.Dims{ + {ID: "%s_mem.swapinRate.average", Name: "in"}, + {ID: "%s_mem.swapoutRate.average", Name: "out"}, + }, + } + + hostDiskIOChartTmpl = module.Chart{ + ID: "%s_disk_io", + Title: "ESXi Host disk IO", + Units: "KiB/s", + Fam: "hosts disk", + Ctx: "vsphere.host_disk_io", + Type: module.Area, + Priority: prioHostDiskIO, + Dims: module.Dims{ + {ID: "%s_disk.read.average", Name: "read"}, + {ID: "%s_disk.write.average", Name: "write", Mul: -1}, + }, + } + hostDiskMaxLatencyChartTmpl = module.Chart{ + ID: "%s_disk_max_latency", + Title: "ESXi Host disk max latency", + Units: "milliseconds", + Fam: "hosts disk", + Ctx: "vsphere.host_disk_max_latency", + Priority: prioHostDiskMaxLatency, + Dims: module.Dims{ + {ID: "%s_disk.maxTotalLatency.latest", Name: "latency"}, + }, + } + + hostNetworkTraffic = module.Chart{ + ID: "%s_net_traffic", + Title: "ESXi Host network traffic", + Units: "KiB/s", + Fam: "hosts net", + Ctx: "vsphere.host_net_traffic", + Type: module.Area, + Priority: prioHostNetworkTraffic, + Dims: module.Dims{ + {ID: "%s_net.bytesRx.average", Name: "received"}, + {ID: "%s_net.bytesTx.average", Name: "sent", Mul: -1}, + }, + } + hostNetworkPacketsChartTmpl = module.Chart{ + ID: "%s_net_packets", + Title: "ESXi Host network packets", + Units: "packets", + Fam: "hosts net", + Ctx: "vsphere.host_net_packets", + Priority: prioHostNetworkPackets, + Dims: module.Dims{ + {ID: "%s_net.packetsRx.summation", Name: "received"}, + {ID: "%s_net.packetsTx.summation", Name: "sent", Mul: -1}, + }, + } + hostNetworkDropsChartTmpl = module.Chart{ + ID: "%s_net_drops_total", + Title: "ESXi Host network drops", + Units: "drops", + Fam: "hosts net", + Ctx: "vsphere.host_net_drops", + Priority: prioHostNetworkDrops, + Dims: module.Dims{ + {ID: "%s_net.droppedRx.summation", Name: "received"}, + {ID: "%s_net.droppedTx.summation", Name: "sent", Mul: -1}, + }, + } + hostNetworkErrorsChartTmpl = module.Chart{ + ID: "%s_net_errors", + Title: "ESXi Host network errors", + Units: "errors", + Fam: "hosts net", + Ctx: "vsphere.host_net_errors", + Priority: prioHostNetworkErrors, + Dims: module.Dims{ + {ID: "%s_net.errorsRx.summation", Name: "received"}, + {ID: "%s_net.errorsTx.summation", Name: "sent", Mul: -1}, + }, + } + + hostOverallStatusChartTmpl = module.Chart{ + ID: "%s_overall_status", + Title: "ESXi Host overall alarm status", + Units: "status", + Fam: "hosts status", + Ctx: "vsphere.host_overall_status", + Priority: prioHostOverallStatus, + Dims: module.Dims{ + {ID: "%s_overall.status.green", Name: "green"}, + {ID: "%s_overall.status.red", Name: "red"}, + {ID: "%s_overall.status.yellow", Name: "yellow"}, + {ID: "%s_overall.status.gray", Name: "gray"}, + }, + } + hostSystemUptimeChartTmpl = module.Chart{ + ID: "%s_system_uptime", + Title: "ESXi Host system uptime", + Units: "seconds", + Fam: "hosts uptime", + Ctx: "vsphere.host_system_uptime", + Priority: prioHostSystemUptime, + Dims: module.Dims{ + {ID: "%s_sys.uptime.latest", Name: "uptime"}, + }, + } +) + +const failedUpdatesLimit = 10 + +func (vs *VSphere) updateCharts() { + for id, fails := range vs.discoveredHosts { + if fails >= failedUpdatesLimit { + vs.removeFromCharts(id) + delete(vs.charted, id) + delete(vs.discoveredHosts, id) + continue + } + + host := vs.resources.Hosts.Get(id) + if host == nil || vs.charted[id] || fails != 0 { + continue + } + + vs.charted[id] = true + charts := newHostCharts(host) + if err := vs.Charts().Add(*charts...); err != nil { + vs.Error(err) + } + } + + for id, fails := range vs.discoveredVMs { + if fails >= failedUpdatesLimit { + vs.removeFromCharts(id) + delete(vs.charted, id) + delete(vs.discoveredVMs, id) + continue + } + + vm := vs.resources.VMs.Get(id) + if vm == nil || vs.charted[id] || fails != 0 { + continue + } + + vs.charted[id] = true + charts := newVMCHarts(vm) + if err := vs.Charts().Add(*charts...); err != nil { + vs.Error(err) + } + } +} + +func newVMCHarts(vm *rs.VM) *module.Charts { + charts := vmChartsTmpl.Copy() + + for _, chart := range *charts { + chart.ID = fmt.Sprintf(chart.ID, vm.ID) + chart.Labels = []module.Label{ + {Key: "datacenter", Value: vm.Hier.DC.Name}, + {Key: "cluster", Value: getVMClusterName(vm)}, + {Key: "host", Value: vm.Hier.Host.Name}, + {Key: "vm", Value: vm.Name}, + } + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, vm.ID) + } + } + + return charts +} + +func getVMClusterName(vm *rs.VM) string { + if vm.Hier.Cluster.Name == vm.Hier.Host.Name { + return "" + } + return vm.Hier.Cluster.Name +} + +func newHostCharts(host *rs.Host) *module.Charts { + charts := hostChartsTmpl.Copy() + + for _, chart := range *charts { + chart.ID = fmt.Sprintf(chart.ID, host.ID) + chart.Labels = []module.Label{ + {Key: "datacenter", Value: host.Hier.DC.Name}, + {Key: "cluster", Value: getHostClusterName(host)}, + {Key: "host", Value: host.Name}, + } + + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, host.ID) + } + } + + return charts +} + +func getHostClusterName(host *rs.Host) string { + if host.Hier.Cluster.Name == host.Name { + return "" + } + return host.Hier.Cluster.Name +} + +func (vs *VSphere) removeFromCharts(prefix string) { + for _, c := range *vs.Charts() { + if strings.HasPrefix(c.ID, prefix) { + c.MarkRemove() + c.MarkNotCreated() + } + } +} + +//func findMetricSeriesByPrefix(ms []performance.MetricSeries, prefix string) []performance.MetricSeries { +// from := sort.Search(len(ms), func(i int) bool { return ms[i].Name >= prefix }) +// +// if from == len(ms) || !strings.HasPrefix(ms[from].Name, prefix) { +// return nil +// } +// +// until := from + 1 +// for until < len(ms) && strings.HasPrefix(ms[until].Name, prefix) { +// until++ +// } +// return ms[from:until] +//} |