Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
100
plugins/inputs/proxmox/README.md
Normal file
100
plugins/inputs/proxmox/README.md
Normal file
|
@ -0,0 +1,100 @@
|
|||
# Proxmox Input Plugin
|
||||
|
||||
The proxmox plugin gathers metrics about containers and VMs using the Proxmox
|
||||
API.
|
||||
|
||||
Telegraf minimum version: Telegraf 1.16.0
|
||||
|
||||
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
|
||||
|
||||
In addition to the plugin-specific configuration settings, plugins support
|
||||
additional global and plugin configuration settings. These settings are used to
|
||||
modify metrics, tags, and field or create aliases and configure ordering, etc.
|
||||
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||
|
||||
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml @sample.conf
|
||||
# Provides metrics from Proxmox nodes (Proxmox Virtual Environment > 6.2).
|
||||
[[inputs.proxmox]]
|
||||
## 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"
|
||||
|
||||
## Node name, defaults to OS hostname
|
||||
## Unless Telegraf is on the same host as Proxmox, setting this is required.
|
||||
# node_name = ""
|
||||
|
||||
## Additional tags of the VM stats data to add as a tag
|
||||
## Supported values are "vmid" and "status"
|
||||
# additional_vmstats_tags = []
|
||||
|
||||
## Optional TLS Config
|
||||
# tls_ca = "/etc/telegraf/ca.pem"
|
||||
# tls_cert = "/etc/telegraf/cert.pem"
|
||||
# tls_key = "/etc/telegraf/key.pem"
|
||||
## Use TLS but skip chain & host verification
|
||||
# insecure_skip_verify = false
|
||||
|
||||
## HTTP response timeout (default: 5s)
|
||||
# response_timeout = "5s"
|
||||
```
|
||||
|
||||
### Permissions
|
||||
|
||||
The plugin will need to have access to the Proxmox API. In Proxmox API tokens
|
||||
are a subset of the corresponding user. This means an API token cannot execute
|
||||
commands that the user cannot either.
|
||||
|
||||
For Telegraf, an API token and user must be provided with at least the
|
||||
PVEAuditor role on /. Below is an example of creating a telegraf user and token
|
||||
and then ensuring the user and token have the correct role:
|
||||
|
||||
```s
|
||||
## Create a influx user with PVEAuditor role
|
||||
pveum user add influx@pve
|
||||
pveum acl modify / -role PVEAuditor -user influx@pve
|
||||
## Create a token with the PVEAuditor role
|
||||
pveum user token add influx@pve monitoring -privsep 1
|
||||
pveum acl modify / -role PVEAuditor -token 'influx@pve!monitoring'
|
||||
```
|
||||
|
||||
See this [Proxmox docs example][1] for further details.
|
||||
|
||||
[1]: https://pve.proxmox.com/wiki/User_Management#_limited_api_token_for_monitoring
|
||||
|
||||
## Metrics
|
||||
|
||||
- proxmox
|
||||
- status
|
||||
- uptime
|
||||
- cpuload
|
||||
- mem_used
|
||||
- mem_total
|
||||
- mem_free
|
||||
- mem_used_percentage
|
||||
- swap_used
|
||||
- swap_total
|
||||
- swap_free
|
||||
- swap_used_percentage
|
||||
- disk_used
|
||||
- disk_total
|
||||
- disk_free
|
||||
- disk_used_percentage
|
||||
|
||||
### Tags
|
||||
|
||||
- node_fqdn - FQDN of the node telegraf is running on
|
||||
- vm_name - Name of the VM/container
|
||||
- vm_fqdn - FQDN of the VM/container
|
||||
- vm_type - Type of the VM/container (lxc, qemu)
|
||||
- vm_id - ID of the VM/container
|
||||
|
||||
## Example Output
|
||||
|
||||
```text
|
||||
proxmox,host=pxnode,node_fqdn=pxnode.example.com,vm_fqdn=vm1.example.com,vm_id=112,vm_name=vm1,vm_type=lxc cpuload=0.147998116735236,disk_free=4461129728i,disk_total=5217320960i,disk_used=756191232i,disk_used_percentage=14,mem_free=1046827008i,mem_total=1073741824i,mem_used=26914816i,mem_used_percentage=2,status="running",swap_free=536698880i,swap_total=536870912i,swap_used=172032i,swap_used_percentage=0,uptime=1643793i 1595457277000000000
|
||||
```
|
293
plugins/inputs/proxmox/proxmox.go
Normal file
293
plugins/inputs/proxmox/proxmox.go
Normal file
|
@ -0,0 +1,293 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package proxmox
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/config"
|
||||
"github.com/influxdata/telegraf/plugins/common/tls"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
type Proxmox struct {
|
||||
BaseURL string `toml:"base_url"`
|
||||
APIToken string `toml:"api_token"`
|
||||
ResponseTimeout config.Duration `toml:"response_timeout"`
|
||||
NodeName string `toml:"node_name"`
|
||||
AdditionalVmstatsTags []string `toml:"additional_vmstats_tags"`
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
tls.ClientConfig
|
||||
|
||||
httpClient *http.Client
|
||||
nodeSearchDomain string
|
||||
|
||||
requestFunction func(apiUrl string, method string, data url.Values) ([]byte, error)
|
||||
}
|
||||
|
||||
func (*Proxmox) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (px *Proxmox) Init() error {
|
||||
// Check parameters
|
||||
for _, v := range px.AdditionalVmstatsTags {
|
||||
switch v {
|
||||
case "vmid", "status":
|
||||
// Do nothing as those are valid values
|
||||
default:
|
||||
return fmt.Errorf("invalid additional vmstats tag %q", v)
|
||||
}
|
||||
}
|
||||
|
||||
// Set hostname as default node name for backwards compatibility
|
||||
if px.NodeName == "" {
|
||||
//nolint:errcheck // best attempt setting of NodeName
|
||||
hostname, _ := os.Hostname()
|
||||
px.NodeName = hostname
|
||||
}
|
||||
|
||||
tlsCfg, err := px.ClientConfig.TLSConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
px.httpClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: tlsCfg,
|
||||
},
|
||||
Timeout: time.Duration(px.ResponseTimeout),
|
||||
}
|
||||
|
||||
px.requestFunction = px.performRequest
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (px *Proxmox) Gather(acc telegraf.Accumulator) error {
|
||||
if err := px.getNodeSearchDomain(); err != nil {
|
||||
return fmt.Errorf("getting search domain failed: %w", err)
|
||||
}
|
||||
|
||||
px.gatherVMData(acc, lxc)
|
||||
px.gatherVMData(acc, qemu)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (px *Proxmox) getNodeSearchDomain() error {
|
||||
apiURL := "/nodes/" + px.NodeName + "/dns"
|
||||
jsonData, err := px.requestFunction(apiURL, http.MethodGet, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("requesting data failed: %w", err)
|
||||
}
|
||||
|
||||
var nodeDNS nodeDNS
|
||||
if err := json.Unmarshal(jsonData, &nodeDNS); err != nil {
|
||||
return fmt.Errorf("decoding message failed: %w", err)
|
||||
}
|
||||
px.nodeSearchDomain = nodeDNS.Data.Searchdomain
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (px *Proxmox) performRequest(apiURL, method string, data url.Values) ([]byte, error) {
|
||||
request, err := http.NewRequest(method, px.BaseURL+apiURL, strings.NewReader(data.Encode()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Add("Authorization", "PVEAPIToken="+px.APIToken)
|
||||
|
||||
resp, err := px.httpClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
responseBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return responseBody, nil
|
||||
}
|
||||
|
||||
func (px *Proxmox) gatherVMData(acc telegraf.Accumulator, rt resourceType) {
|
||||
vmStats, err := px.getVMStats(rt)
|
||||
if err != nil {
|
||||
px.Log.Errorf("Error getting VM stats: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, vmStat := range vmStats.Data {
|
||||
vmConfig, err := px.getVMConfig(vmStat.ID, rt)
|
||||
if err != nil {
|
||||
px.Log.Errorf("Error getting VM config: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if vmConfig.Data.Template == 1 {
|
||||
px.Log.Debugf("Ignoring template VM %s (%s)", vmStat.ID, vmStat.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
currentVMStatus, err := px.getCurrentVMStatus(rt, vmStat.ID)
|
||||
if err != nil {
|
||||
px.Log.Errorf("Error getting VM current VM status: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
vmFQDN := vmConfig.Data.Hostname
|
||||
if vmFQDN == "" {
|
||||
vmFQDN = vmStat.Name
|
||||
}
|
||||
domain := vmConfig.Data.Searchdomain
|
||||
if domain == "" {
|
||||
domain = px.nodeSearchDomain
|
||||
}
|
||||
if domain != "" {
|
||||
vmFQDN += "." + domain
|
||||
}
|
||||
|
||||
nodeFQDN := px.NodeName
|
||||
if px.nodeSearchDomain != "" {
|
||||
nodeFQDN += "." + domain
|
||||
}
|
||||
|
||||
tags := map[string]string{
|
||||
"node_fqdn": nodeFQDN,
|
||||
"vm_name": vmStat.Name,
|
||||
"vm_fqdn": vmFQDN,
|
||||
"vm_type": string(rt),
|
||||
}
|
||||
if slices.Contains(px.AdditionalVmstatsTags, "vmid") {
|
||||
tags["vm_id"] = vmStat.ID.String()
|
||||
}
|
||||
if slices.Contains(px.AdditionalVmstatsTags, "status") {
|
||||
tags["status"] = currentVMStatus.Status
|
||||
}
|
||||
|
||||
memMetrics := getByteMetrics(currentVMStatus.TotalMem, currentVMStatus.UsedMem)
|
||||
swapMetrics := getByteMetrics(currentVMStatus.TotalSwap, currentVMStatus.UsedSwap)
|
||||
diskMetrics := getByteMetrics(currentVMStatus.TotalDisk, currentVMStatus.UsedDisk)
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"status": currentVMStatus.Status,
|
||||
"uptime": jsonNumberToInt64(currentVMStatus.Uptime),
|
||||
"cpuload": jsonNumberToFloat64(currentVMStatus.CPULoad),
|
||||
"mem_used": memMetrics.used,
|
||||
"mem_total": memMetrics.total,
|
||||
"mem_free": memMetrics.free,
|
||||
"mem_used_percentage": memMetrics.usedPercentage,
|
||||
"swap_used": swapMetrics.used,
|
||||
"swap_total": swapMetrics.total,
|
||||
"swap_free": swapMetrics.free,
|
||||
"swap_used_percentage": swapMetrics.usedPercentage,
|
||||
"disk_used": diskMetrics.used,
|
||||
"disk_total": diskMetrics.total,
|
||||
"disk_free": diskMetrics.free,
|
||||
"disk_used_percentage": diskMetrics.usedPercentage,
|
||||
}
|
||||
acc.AddFields("proxmox", fields, tags)
|
||||
}
|
||||
}
|
||||
|
||||
func (px *Proxmox) getCurrentVMStatus(rt resourceType, id json.Number) (vmStat, error) {
|
||||
apiURL := "/nodes/" + px.NodeName + "/" + string(rt) + "/" + string(id) + "/status/current"
|
||||
jsonData, err := px.requestFunction(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 (px *Proxmox) getVMStats(rt resourceType) (vmStats, error) {
|
||||
apiURL := "/nodes/" + px.NodeName + "/" + string(rt)
|
||||
jsonData, err := px.requestFunction(apiURL, http.MethodGet, nil)
|
||||
if err != nil {
|
||||
return vmStats{}, err
|
||||
}
|
||||
|
||||
var vmStatistics vmStats
|
||||
err = json.Unmarshal(jsonData, &vmStatistics)
|
||||
if err != nil {
|
||||
return vmStats{}, err
|
||||
}
|
||||
|
||||
return vmStatistics, nil
|
||||
}
|
||||
|
||||
func (px *Proxmox) getVMConfig(vmID json.Number, rt resourceType) (vmConfig, error) {
|
||||
apiURL := "/nodes/" + px.NodeName + "/" + string(rt) + "/" + string(vmID) + "/config"
|
||||
jsonData, err := px.requestFunction(apiURL, http.MethodGet, nil)
|
||||
if err != nil {
|
||||
return vmConfig{}, err
|
||||
}
|
||||
|
||||
var vmCfg vmConfig
|
||||
err = json.Unmarshal(jsonData, &vmCfg)
|
||||
if err != nil {
|
||||
return vmConfig{}, err
|
||||
}
|
||||
|
||||
return vmCfg, nil
|
||||
}
|
||||
|
||||
func getByteMetrics(total, used json.Number) metrics {
|
||||
int64Total := jsonNumberToInt64(total)
|
||||
int64Used := jsonNumberToInt64(used)
|
||||
int64Free := int64Total - int64Used
|
||||
usedPercentage := 0.0
|
||||
if int64Total != 0 {
|
||||
usedPercentage = float64(int64Used) * 100 / float64(int64Total)
|
||||
}
|
||||
|
||||
return metrics{
|
||||
total: int64Total,
|
||||
used: int64Used,
|
||||
free: int64Free,
|
||||
usedPercentage: usedPercentage,
|
||||
}
|
||||
}
|
||||
|
||||
func jsonNumberToInt64(value json.Number) int64 {
|
||||
int64Value, err := value.Int64()
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return int64Value
|
||||
}
|
||||
|
||||
func jsonNumberToFloat64(value json.Number) float64 {
|
||||
float64Value, err := value.Float64()
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return float64Value
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("proxmox", func() telegraf.Input {
|
||||
return &Proxmox{}
|
||||
})
|
||||
}
|
257
plugins/inputs/proxmox/proxmox_test.go
Normal file
257
plugins/inputs/proxmox/proxmox_test.go
Normal file
|
@ -0,0 +1,257 @@
|
|||
package proxmox
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/metric"
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
var nodeSearchDomainTestData = `{"data":{"search":"test.example.com","dns1":"1.0.0.1"}}`
|
||||
var qemuTestData = `{"data":[{"name":"qemu1","status":"running","maxdisk":10737418240,"cpu":0.029336643550795,"vmid":"113","uptime":2159739,` +
|
||||
`"disk":0,"maxmem":2147483648,"mem":1722451796}]}`
|
||||
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"},{"vmid":112,"type":"lxc",` +
|
||||
`"uptime":2078164,"swap":9412608,"disk":"744189952","maxmem":536870912,"mem":98500608,"maxswap":536870912,"cpu":0.00371567669193613,` +
|
||||
`"status":"running","maxdisk":"5217320960","name":"container2"}]}`
|
||||
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(apiURL, _ string, _ url.Values) ([]byte, error) {
|
||||
var bytedata = []byte("")
|
||||
|
||||
if strings.HasSuffix(apiURL, "dns") {
|
||||
bytedata = []byte(nodeSearchDomainTestData)
|
||||
} else if strings.HasSuffix(apiURL, "qemu") {
|
||||
bytedata = []byte(qemuTestData)
|
||||
} else if strings.HasSuffix(apiURL, "113/config") {
|
||||
bytedata = []byte(qemuConfigTestData)
|
||||
} else if strings.HasSuffix(apiURL, "lxc") {
|
||||
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
|
||||
}
|
||||
|
||||
func TestGetNodeSearchDomain(t *testing.T) {
|
||||
px := &Proxmox{
|
||||
NodeName: "testnode",
|
||||
Log: testutil.Logger{},
|
||||
}
|
||||
require.NoError(t, px.Init())
|
||||
px.requestFunction = performTestRequest
|
||||
|
||||
require.NoError(t, px.getNodeSearchDomain())
|
||||
require.Equal(t, "test.example.com", px.nodeSearchDomain)
|
||||
}
|
||||
|
||||
func TestGatherLxcData(t *testing.T) {
|
||||
px := &Proxmox{
|
||||
NodeName: "testnode",
|
||||
Log: testutil.Logger{},
|
||||
nodeSearchDomain: "test.example.com",
|
||||
}
|
||||
require.NoError(t, px.Init())
|
||||
px.requestFunction = performTestRequest
|
||||
|
||||
var acc testutil.Accumulator
|
||||
px.gatherVMData(&acc, lxc)
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
metric.New(
|
||||
"proxmox",
|
||||
map[string]string{
|
||||
"node_fqdn": "testnode.test.example.com",
|
||||
"vm_name": "container1",
|
||||
"vm_fqdn": "container1.test.example.com",
|
||||
"vm_type": "lxc",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"status": "running",
|
||||
"uptime": int64(2078164),
|
||||
"cpuload": float64(0.00371567669193613),
|
||||
"mem_used": int64(98500608),
|
||||
"mem_total": int64(536870912),
|
||||
"mem_free": int64(438370304),
|
||||
"mem_used_percentage": float64(18.34716796875),
|
||||
"swap_used": int64(9412608),
|
||||
"swap_total": int64(536870912),
|
||||
"swap_free": int64(527458304),
|
||||
"swap_used_percentage": float64(1.75323486328125),
|
||||
"disk_used": int64(744189952),
|
||||
"disk_total": int64(5217320960),
|
||||
"disk_free": int64(4473131008),
|
||||
"disk_used_percentage": float64(14.26383306117322),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
}
|
||||
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
|
||||
}
|
||||
|
||||
func TestGatherQemuData(t *testing.T) {
|
||||
px := &Proxmox{
|
||||
NodeName: "testnode",
|
||||
Log: testutil.Logger{},
|
||||
nodeSearchDomain: "test.example.com",
|
||||
}
|
||||
require.NoError(t, px.Init())
|
||||
px.requestFunction = performTestRequest
|
||||
|
||||
var acc testutil.Accumulator
|
||||
px.gatherVMData(&acc, qemu)
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
metric.New(
|
||||
"proxmox",
|
||||
map[string]string{
|
||||
"node_fqdn": "testnode.test.example.com",
|
||||
"vm_name": "qemu1",
|
||||
"vm_fqdn": "qemu1.test.example.com",
|
||||
"vm_type": "qemu",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"status": "running",
|
||||
"uptime": int64(2159739),
|
||||
"cpuload": float64(0.029336643550795),
|
||||
"mem_used": int64(1722451796),
|
||||
"mem_total": int64(2147483648),
|
||||
"mem_free": int64(425031852),
|
||||
"mem_used_percentage": float64(80.20791206508875),
|
||||
"swap_used": int64(0),
|
||||
"swap_total": int64(0),
|
||||
"swap_free": int64(0),
|
||||
"swap_used_percentage": float64(0),
|
||||
"disk_used": int64(0),
|
||||
"disk_total": int64(10737418240),
|
||||
"disk_free": int64(10737418240),
|
||||
"disk_used_percentage": float64(0),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
}
|
||||
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
|
||||
}
|
||||
|
||||
func TestGatherLxcDataWithID(t *testing.T) {
|
||||
px := &Proxmox{
|
||||
NodeName: "testnode",
|
||||
AdditionalVmstatsTags: []string{"vmid"},
|
||||
Log: testutil.Logger{},
|
||||
nodeSearchDomain: "test.example.com",
|
||||
}
|
||||
require.NoError(t, px.Init())
|
||||
px.requestFunction = performTestRequest
|
||||
|
||||
var acc testutil.Accumulator
|
||||
px.gatherVMData(&acc, lxc)
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
metric.New(
|
||||
"proxmox",
|
||||
map[string]string{
|
||||
"node_fqdn": "testnode.test.example.com",
|
||||
"vm_name": "container1",
|
||||
"vm_fqdn": "container1.test.example.com",
|
||||
"vm_type": "lxc",
|
||||
"vm_id": "111",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"status": "running",
|
||||
"uptime": int64(2078164),
|
||||
"cpuload": float64(0.00371567669193613),
|
||||
"mem_used": int64(98500608),
|
||||
"mem_total": int64(536870912),
|
||||
"mem_free": int64(438370304),
|
||||
"mem_used_percentage": float64(18.34716796875),
|
||||
"swap_used": int64(9412608),
|
||||
"swap_total": int64(536870912),
|
||||
"swap_free": int64(527458304),
|
||||
"swap_used_percentage": float64(1.75323486328125),
|
||||
"disk_used": int64(744189952),
|
||||
"disk_total": int64(5217320960),
|
||||
"disk_free": int64(4473131008),
|
||||
"disk_used_percentage": float64(14.26383306117322),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
}
|
||||
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
|
||||
}
|
||||
|
||||
func TestGatherQemuDataWithID(t *testing.T) {
|
||||
px := &Proxmox{
|
||||
NodeName: "testnode",
|
||||
AdditionalVmstatsTags: []string{"vmid"},
|
||||
Log: testutil.Logger{},
|
||||
nodeSearchDomain: "test.example.com",
|
||||
}
|
||||
require.NoError(t, px.Init())
|
||||
px.requestFunction = performTestRequest
|
||||
|
||||
var acc testutil.Accumulator
|
||||
px.gatherVMData(&acc, qemu)
|
||||
|
||||
expected := []telegraf.Metric{
|
||||
metric.New(
|
||||
"proxmox",
|
||||
map[string]string{
|
||||
"node_fqdn": "testnode.test.example.com",
|
||||
"vm_name": "qemu1",
|
||||
"vm_fqdn": "qemu1.test.example.com",
|
||||
"vm_type": "qemu",
|
||||
"vm_id": "113",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"status": "running",
|
||||
"uptime": int64(2159739),
|
||||
"cpuload": float64(0.029336643550795),
|
||||
"mem_used": int64(1722451796),
|
||||
"mem_total": int64(2147483648),
|
||||
"mem_free": int64(425031852),
|
||||
"mem_used_percentage": float64(80.20791206508875),
|
||||
"swap_used": int64(0),
|
||||
"swap_total": int64(0),
|
||||
"swap_free": int64(0),
|
||||
"swap_used_percentage": float64(0),
|
||||
"disk_used": int64(0),
|
||||
"disk_total": int64(10737418240),
|
||||
"disk_free": int64(10737418240),
|
||||
"disk_used_percentage": float64(0),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
}
|
||||
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
|
||||
}
|
||||
|
||||
func TestGather(t *testing.T) {
|
||||
px := &Proxmox{
|
||||
NodeName: "testnode",
|
||||
Log: testutil.Logger{},
|
||||
}
|
||||
require.NoError(t, px.Init())
|
||||
px.requestFunction = performTestRequest
|
||||
|
||||
var acc testutil.Accumulator
|
||||
require.NoError(t, px.Gather(&acc))
|
||||
|
||||
// Results from both tests above
|
||||
require.Equal(t, 30, acc.NFields())
|
||||
}
|
24
plugins/inputs/proxmox/sample.conf
Normal file
24
plugins/inputs/proxmox/sample.conf
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Provides metrics from Proxmox nodes (Proxmox Virtual Environment > 6.2).
|
||||
[[inputs.proxmox]]
|
||||
## 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"
|
||||
|
||||
## Node name, defaults to OS hostname
|
||||
## Unless Telegraf is on the same host as Proxmox, setting this is required.
|
||||
# node_name = ""
|
||||
|
||||
## Additional tags of the VM stats data to add as a tag
|
||||
## Supported values are "vmid" and "status"
|
||||
# additional_vmstats_tags = []
|
||||
|
||||
## Optional TLS Config
|
||||
# tls_ca = "/etc/telegraf/ca.pem"
|
||||
# tls_cert = "/etc/telegraf/cert.pem"
|
||||
# tls_key = "/etc/telegraf/key.pem"
|
||||
## Use TLS but skip chain & host verification
|
||||
# insecure_skip_verify = false
|
||||
|
||||
## HTTP response timeout (default: 5s)
|
||||
# response_timeout = "5s"
|
55
plugins/inputs/proxmox/structs.go
Normal file
55
plugins/inputs/proxmox/structs.go
Normal file
|
@ -0,0 +1,55 @@
|
|||
package proxmox
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
var (
|
||||
qemu resourceType = "qemu"
|
||||
lxc resourceType = "lxc"
|
||||
)
|
||||
|
||||
type resourceType string
|
||||
|
||||
type vmStats struct {
|
||||
Data []vmStat `json:"data"`
|
||||
}
|
||||
|
||||
type vmCurrentStats struct {
|
||||
Data vmStat `json:"data"`
|
||||
}
|
||||
|
||||
type vmStat struct {
|
||||
ID json.Number `json:"vmid"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
UsedMem json.Number `json:"mem"`
|
||||
TotalMem json.Number `json:"maxmem"`
|
||||
UsedDisk json.Number `json:"disk"`
|
||||
TotalDisk json.Number `json:"maxdisk"`
|
||||
UsedSwap json.Number `json:"swap"`
|
||||
TotalSwap json.Number `json:"maxswap"`
|
||||
Uptime json.Number `json:"uptime"`
|
||||
CPULoad json.Number `json:"cpu"`
|
||||
}
|
||||
|
||||
type vmConfig struct {
|
||||
Data struct {
|
||||
Searchdomain string `json:"searchdomain"`
|
||||
Hostname string `json:"hostname"`
|
||||
Template int `json:"template"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type nodeDNS struct {
|
||||
Data struct {
|
||||
Searchdomain string `json:"search"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type metrics struct {
|
||||
total int64
|
||||
used int64
|
||||
free int64
|
||||
usedPercentage float64
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue