From 9c2979dcedda7e007332d1f9afa4701295373796 Mon Sep 17 00:00:00 2001 From: tlusser-inv <39266023+tlusser-inv@users.noreply.github.com> Date: Wed, 21 Oct 2020 16:50:29 +0200 Subject: [PATCH] Fix wrong memory measurements of containers and vms (#8290) --- plugins/inputs/proxmox/README.md | 2 ++ plugins/inputs/proxmox/proxmox.go | 48 +++++++++++++++++++++----- plugins/inputs/proxmox/proxmox_test.go | 10 ++++-- plugins/inputs/proxmox/structs.go | 7 +++- 4 files changed, 55 insertions(+), 12 deletions(-) diff --git a/plugins/inputs/proxmox/README.md b/plugins/inputs/proxmox/README.md index ac81633a3..24e39ade2 100644 --- a/plugins/inputs/proxmox/README.md +++ b/plugins/inputs/proxmox/README.md @@ -11,6 +11,8 @@ Telegraf minimum version: Telegraf 1.16.0 ## API connection configuration. The API token was introduced in Proxmox v6.2. Required permissions for user and token: PVEAuditor role on /. base_url = "https://localhost:8006/api2/json" api_token = "USER@REALM!TOKENID=UUID" + ## Optional node name config + # node_name = "localhost" ## Optional TLS Config # tls_ca = "/etc/telegraf/ca.pem" diff --git a/plugins/inputs/proxmox/proxmox.go b/plugins/inputs/proxmox/proxmox.go index 13dcb4a95..7c1435684 100644 --- a/plugins/inputs/proxmox/proxmox.go +++ b/plugins/inputs/proxmox/proxmox.go @@ -2,6 +2,7 @@ package proxmox import ( "encoding/json" + "errors" "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/plugins/inputs" "io/ioutil" @@ -48,11 +49,10 @@ func (px *Proxmox) Gather(acc telegraf.Accumulator) error { } func (px *Proxmox) Init() error { - hostname, err := os.Hostname() - if err != nil { - return err + + if px.NodeName == "" { + return errors.New("node_name must be configured") } - px.hostname = hostname tlsCfg, err := px.ClientConfig.TLSConfig() if err != nil { @@ -73,11 +73,15 @@ func init() { requestFunction: performRequest, } + // Set hostname as default node name for backwards compatibility + hostname, _ := os.Hostname() + px.NodeName = hostname + inputs.Add("proxmox", func() telegraf.Input { return &px }) } func getNodeSearchDomain(px *Proxmox) error { - apiUrl := "/nodes/" + px.hostname + "/dns" + apiUrl := "/nodes/" + px.NodeName + "/dns" jsonData, err := px.requestFunction(px, apiUrl, http.MethodGet, nil) if err != nil { return err @@ -88,6 +92,10 @@ func getNodeSearchDomain(px *Proxmox) error { if err != nil { return err } + + if nodeDns.Data.Searchdomain == "" { + return errors.New("node_name not found") + } px.nodeSearchDomain = nodeDns.Data.Searchdomain return nil @@ -137,7 +145,12 @@ func gatherVmData(px *Proxmox, acc telegraf.Accumulator, rt ResourceType) { return } tags := getTags(px, vmStat.Name, vmConfig, rt) - fields, err := getFields(vmStat) + currentVMStatus, err := getCurrentVMStatus(px, rt, vmStat.ID) + if err != nil { + px.Log.Error("Error getting VM curent VM status: %v", err) + return + } + fields, err := getFields(currentVMStatus) if err != nil { px.Log.Error("Error getting VM measurements: %v", err) return @@ -146,8 +159,25 @@ func gatherVmData(px *Proxmox, acc telegraf.Accumulator, rt ResourceType) { } } +func getCurrentVMStatus(px *Proxmox, rt ResourceType, id string) (VmStat, error) { + apiUrl := "/nodes/" + px.NodeName + "/" + string(rt) + "/" + id + "/status/current" + + jsonData, err := px.requestFunction(px, apiUrl, http.MethodGet, nil) + if err != nil { + return VmStat{}, err + } + + var currentVmStatus VmCurrentStats + err = json.Unmarshal(jsonData, ¤tVmStatus) + if err != nil { + return VmStat{}, err + } + + return currentVmStatus.Data, nil +} + func getVmStats(px *Proxmox, rt ResourceType) (VmStats, error) { - apiUrl := "/nodes/" + px.hostname + "/" + string(rt) + apiUrl := "/nodes/" + px.NodeName + "/" + string(rt) jsonData, err := px.requestFunction(px, apiUrl, http.MethodGet, nil) if err != nil { return VmStats{}, err @@ -163,7 +193,7 @@ func getVmStats(px *Proxmox, rt ResourceType) (VmStats, error) { } func getVmConfig(px *Proxmox, vmId string, rt ResourceType) (VmConfig, error) { - apiUrl := "/nodes/" + px.hostname + "/" + string(rt) + "/" + vmId + "/config" + apiUrl := "/nodes/" + px.NodeName + "/" + string(rt) + "/" + vmId + "/config" jsonData, err := px.requestFunction(px, apiUrl, http.MethodGet, nil) if err != nil { return VmConfig{}, err @@ -245,7 +275,7 @@ func getTags(px *Proxmox, name string, vmConfig VmConfig, rt ResourceType) map[s fqdn := hostname + "." + domain return map[string]string{ - "node_fqdn": px.hostname + "." + px.nodeSearchDomain, + "node_fqdn": px.NodeName + "." + px.nodeSearchDomain, "vm_name": name, "vm_fqdn": fqdn, "vm_type": string(rt), diff --git a/plugins/inputs/proxmox/proxmox_test.go b/plugins/inputs/proxmox/proxmox_test.go index 274ebdf69..524a105e7 100644 --- a/plugins/inputs/proxmox/proxmox_test.go +++ b/plugins/inputs/proxmox/proxmox_test.go @@ -14,6 +14,8 @@ var qemuTestData = `{"data":[{"name":"qemu1","status":"running","maxdisk":107374 var qemuConfigTestData = `{"data":{"hostname":"qemu1","searchdomain":"test.example.com"}}` var lxcTestData = `{"data":[{"vmid":"111","type":"lxc","uptime":2078164,"swap":9412608,"disk":"744189952","maxmem":536870912,"mem":98500608,"maxswap":536870912,"cpu":0.00371567669193613,"status":"running","maxdisk":"5217320960","name":"container1"}]}` var lxcConfigTestData = `{"data":{"hostname":"container1","searchdomain":"test.example.com"}}` +var lxcCurrentStatusTestData = `{"data":{"vmid":"111","type":"lxc","uptime":2078164,"swap":9412608,"disk":"744189952","maxmem":536870912,"mem":98500608,"maxswap":536870912,"cpu":0.00371567669193613,"status":"running","maxdisk":"5217320960","name":"container1"}}` +var qemuCurrentStatusTestData = `{"data":{"name":"qemu1","status":"running","maxdisk":10737418240,"cpu":0.029336643550795,"vmid":"113","uptime":2159739,"disk":0,"maxmem":2147483648,"mem":1722451796}}` func performTestRequest(px *Proxmox, apiUrl string, method string, data url.Values) ([]byte, error) { var bytedata = []byte("") @@ -28,6 +30,10 @@ func performTestRequest(px *Proxmox, apiUrl string, method string, data url.Valu bytedata = []byte(lxcTestData) } else if strings.HasSuffix(apiUrl, "111/config") { bytedata = []byte(lxcConfigTestData) + } else if strings.HasSuffix(apiUrl, "111/status/current") { + bytedata = []byte(lxcCurrentStatusTestData) + } else if strings.HasSuffix(apiUrl, "113/status/current") { + bytedata = []byte(qemuCurrentStatusTestData) } return bytedata, nil @@ -36,12 +42,12 @@ func performTestRequest(px *Proxmox, apiUrl string, method string, data url.Valu func setUp(t *testing.T) *Proxmox { px := &Proxmox{ requestFunction: performTestRequest, + NodeName: "testnode", } require.NoError(t, px.Init()) - // Override hostname and logger for test - px.hostname = "testnode" + // Override logger for test px.Log = testutil.Logger{} return px } diff --git a/plugins/inputs/proxmox/structs.go b/plugins/inputs/proxmox/structs.go index eef5dffff..461e71d76 100644 --- a/plugins/inputs/proxmox/structs.go +++ b/plugins/inputs/proxmox/structs.go @@ -13,9 +13,10 @@ type Proxmox struct { BaseURL string `toml:"base_url"` APIToken string `toml:"api_token"` ResponseTimeout internal.Duration `toml:"response_timeout"` + NodeName string `toml:"node_name"` + tls.ClientConfig - hostname string httpClient *http.Client nodeSearchDomain string @@ -34,6 +35,10 @@ type VmStats struct { Data []VmStat `json:"data"` } +type VmCurrentStats struct { + Data VmStat `json:"data"` +} + type VmStat struct { ID string `json:"vmid"` Name string `json:"name"`