From d7aac710125a83c69970fc4903d0a4a4d5d4f784 Mon Sep 17 00:00:00 2001 From: Mario Castro Date: Fri, 28 Dec 2018 14:56:17 +0100 Subject: [PATCH] Fix nil pointers accesses causing panics in Metricbeat Vsphere module (#9784) In Vsphere module, some fields returned by the Vsphere library contain pointers to some values that could potentially be nil. With this PR, we do a nil-check prior every access to any of those fields to avoid their writing in case they are nil and protecting Metricbeat from panicking. (cherry picked from commit 7c31cedc1b961be0b31362639ad171a82c1021a4) --- CHANGELOG.next.asciidoc | 1 + metricbeat/module/vsphere/host/host.go | 47 +++++++--------- .../vsphere/virtualmachine/virtualmachine.go | 53 ++++++++----------- 3 files changed, 42 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index c3cbbe0ee97..70d61a6bd18 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -41,6 +41,7 @@ https://github.com/elastic/beats/compare/1035569addc4a3b29ffa14f8a08c27c1ace16ef *Journalbeat* *Metricbeat* +- Fix panics in vsphere module when certain values where not returned by the API. {pull}9784[9784] *Packetbeat* diff --git a/metricbeat/module/vsphere/host/host.go b/metricbeat/module/vsphere/host/host.go index b5db91d21f1..526c3747856 100644 --- a/metricbeat/module/vsphere/host/host.go +++ b/metricbeat/module/vsphere/host/host.go @@ -38,6 +38,8 @@ import ( "github.com/vmware/govmomi/vim25/types" ) +var logger = logp.NewLogger("vsphere") + func init() { mb.Registry.MustAddMetricSet("vsphere", "host", New, mb.DefaultMetricSet(), @@ -111,40 +113,27 @@ func (m *MetricSet) Fetch() ([]common.MapStr, error) { } for _, hs := range hst { - totalCPU := int64(hs.Summary.Hardware.CpuMhz) * int64(hs.Summary.Hardware.NumCpuCores) - freeCPU := int64(totalCPU) - int64(hs.Summary.QuickStats.OverallCpuUsage) - freeMemory := int64(hs.Summary.Hardware.MemorySize) - (int64(hs.Summary.QuickStats.OverallMemoryUsage) * 1024 * 1024) - - event := common.MapStr{ - "name": hs.Summary.Config.Name, - "cpu": common.MapStr{ - "used": common.MapStr{ - "mhz": hs.Summary.QuickStats.OverallCpuUsage, - }, - "total": common.MapStr{ - "mhz": totalCPU, - }, - "free": common.MapStr{ - "mhz": freeCPU, - }, - }, - "memory": common.MapStr{ - "used": common.MapStr{ - "bytes": (int64(hs.Summary.QuickStats.OverallMemoryUsage) * 1024 * 1024), - }, - "total": common.MapStr{ - "bytes": hs.Summary.Hardware.MemorySize, - }, - "free": common.MapStr{ - "bytes": freeMemory, - }, - }, + + event := common.MapStr{} + + event["name"] = hs.Summary.Config.Name + event.Put("cpu.used.mhz", hs.Summary.QuickStats.OverallCpuUsage) + event.Put("memory.used.bytes", int64(hs.Summary.QuickStats.OverallMemoryUsage)*1024*1024) + + if hs.Summary.Hardware != nil { + totalCPU := int64(hs.Summary.Hardware.CpuMhz) * int64(hs.Summary.Hardware.NumCpuCores) + event.Put("cpu.total.mhz", totalCPU) + event.Put("cpu.free.mhz", int64(totalCPU)-int64(hs.Summary.QuickStats.OverallCpuUsage)) + event.Put("memory.free.bytes", int64(hs.Summary.Hardware.MemorySize)-(int64(hs.Summary.QuickStats.OverallMemoryUsage)*1024*1024)) + event.Put("memory.total.bytes", hs.Summary.Hardware.MemorySize) + } else { + logger.Debug("'Hardware' or 'Summary' data not found. This is either a parsing error from vsphere library, an error trying to reach host/guest or incomplete information returned from host/guest") } if hs.Summary.Host != nil { networkNames, err := getNetworkNames(ctx, c, hs.Summary.Host.Reference()) if err != nil { - logp.Debug("vsphere", err.Error()) + logger.Debugf("error trying to get network names: %s", err.Error()) } else { if len(networkNames) > 0 { event["network_names"] = networkNames diff --git a/metricbeat/module/vsphere/virtualmachine/virtualmachine.go b/metricbeat/module/vsphere/virtualmachine/virtualmachine.go index 4fad5d6a688..7474f3d319d 100644 --- a/metricbeat/module/vsphere/virtualmachine/virtualmachine.go +++ b/metricbeat/module/vsphere/virtualmachine/virtualmachine.go @@ -39,6 +39,8 @@ import ( "github.com/vmware/govmomi/vim25/types" ) +var logger = logp.NewLogger("vsphere") + func init() { mb.Registry.MustAddMetricSet("vsphere", "virtualmachine", New, mb.DefaultMetricSet(), @@ -138,49 +140,40 @@ func (m *MetricSet) Fetch() ([]common.MapStr, error) { freeMemory := (int64(vm.Summary.Config.MemorySizeMB) * 1024 * 1024) - (int64(vm.Summary.QuickStats.GuestMemoryUsage) * 1024 * 1024) - event := common.MapStr{ - "host": vm.Summary.Runtime.Host.Value, - "name": vm.Summary.Config.Name, - "cpu": common.MapStr{ - "used": common.MapStr{ - "mhz": vm.Summary.QuickStats.OverallCpuUsage, - }, - }, - "memory": common.MapStr{ - "used": common.MapStr{ - "guest": common.MapStr{ - "bytes": (int64(vm.Summary.QuickStats.GuestMemoryUsage) * 1024 * 1024), - }, - "host": common.MapStr{ - "bytes": (int64(vm.Summary.QuickStats.HostMemoryUsage) * 1024 * 1024), - }, - }, - "total": common.MapStr{ - "guest": common.MapStr{ - "bytes": (int64(vm.Summary.Config.MemorySizeMB) * 1024 * 1024), - }, - }, - "free": common.MapStr{ - "guest": common.MapStr{ - "bytes": freeMemory, - }, - }, - }, + event := common.MapStr{} + + event["name"] = vm.Summary.Config.Name + event.Put("cpu.used.mhz", vm.Summary.QuickStats.OverallCpuUsage) + event.Put("memory.used.guest.bytes", int64(vm.Summary.QuickStats.GuestMemoryUsage)*1024*1024) + event.Put("memory.used.host.bytes", int64(vm.Summary.QuickStats.HostMemoryUsage)*1024*1024) + event.Put("memory.total.guest.bytes", int64(vm.Summary.Config.MemorySizeMB)*1024*1024) + event.Put("memory.free.guest.bytes", freeMemory) + + if vm.Summary.Runtime.Host != nil { + event["host"] = vm.Summary.Runtime.Host.Value + } else { + logger.Debug("'Host', 'Runtime' or 'Summary' data not found. This is either a parsing error " + + "from vsphere library, an error trying to reach host/guest or incomplete information returned " + + "from host/guest") } // Get custom fields (attributes) values if get_custom_fields is true. - if m.GetCustomFields { + if m.GetCustomFields && vm.Summary.CustomValue != nil { customFields := getCustomFields(vm.Summary.CustomValue, customFieldsMap) if len(customFields) > 0 { event["custom_fields"] = customFields } + } else { + logger.Debug("custom fields not activated or custom values not found/parse in Summary data. This " + + "is either a parsing error from vsphere library, an error trying to reach host/guest or incomplete " + + "information returned from host/guest") } if vm.Summary.Vm != nil { networkNames, err := getNetworkNames(c, vm.Summary.Vm.Reference()) if err != nil { - logp.Debug("vsphere", err.Error()) + logger.Debug(err.Error()) } else { if len(networkNames) > 0 { event["network_names"] = networkNames