Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8f9e0c852 | ||
|
|
e5a5e6416b | ||
|
|
c4287c37bc |
@@ -58,12 +58,19 @@ metrics:
|
||||
sdn: true # Enable collection of software-defined network (SDN) metrics.
|
||||
```
|
||||
|
||||
The cluster state collector exposes `pve_cluster_mode`, where `1` means that
|
||||
Proxmox VE is configured as a cluster and `0` means that it is a standalone node.
|
||||
|
||||
The `pve_node_subscription_status` metric uses `0` when no subscription is
|
||||
configured, `1` for an active subscription, and `2` for an expired or otherwise
|
||||
unusable subscription.
|
||||
|
||||
## Build
|
||||
|
||||
To build the Docker image for PVE Exporter, use the following command:
|
||||
|
||||
```sh
|
||||
docker build --rm -t harbor.imtm.cz/private/pve-exporter:version .
|
||||
docker build --rm -t gitea.lostak.dev/lostakj/pve-exporter:version .
|
||||
```
|
||||
|
||||
Replace `version` with the appropriate version tag you want to use.
|
||||
@@ -73,7 +80,7 @@ Replace `version` with the appropriate version tag you want to use.
|
||||
To run the Docker image, use the following command:
|
||||
|
||||
```sh
|
||||
docker run --rm -d -p 9090:9090 --name pve-exporter harbor.imtm.cz/private/pve-exporter:version
|
||||
docker run --rm -d -p 9090:9090 --name pve-exporter gitea.lostak.dev/lostakj/pve-exporter:version
|
||||
```
|
||||
|
||||
Replace `version` with the appropriate version tag you used during the build.
|
||||
|
||||
@@ -14,6 +14,7 @@ type PveClusterStateCollector struct {
|
||||
|
||||
nodes *TTLGaugeVec // Count of nodes prometheus gauge.
|
||||
quorate *TTLGaugeVec // Cluster quorum state prometheus gauge.
|
||||
clusterMode *TTLGaugeVec // PVE cluster mode prometheus gauge.
|
||||
}
|
||||
|
||||
// Create new instance of PVE cluster state collector.
|
||||
@@ -42,6 +43,17 @@ func NewPveClusterStateCollector(apiClient *proxmox.PveApiClient, registry *TTLR
|
||||
5*time.Minute,
|
||||
)
|
||||
c.registry.Register(c.quorate)
|
||||
|
||||
// PVE cluster mode gauge.
|
||||
c.clusterMode = NewTTLGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "pve_cluster_mode",
|
||||
Help: "PVE cluster mode (1 = cluster, 0 = standalone node).",
|
||||
},
|
||||
[]string{"cluster"},
|
||||
5*time.Minute,
|
||||
)
|
||||
c.registry.Register(c.clusterMode)
|
||||
c.registry.StartCleanupLoop(5 * time.Second)
|
||||
|
||||
return &c
|
||||
@@ -54,9 +66,10 @@ func (c *PveClusterStateCollector) CollectMetrics() error {
|
||||
return err
|
||||
}
|
||||
|
||||
l := prometheus.Labels{"cluster": cluster.Name}
|
||||
l := prometheus.Labels{"cluster": cluster.GetClusterName()}
|
||||
c.nodes.With(l).Set(float64(cluster.Nodes))
|
||||
c.quorate.With(l).Set(float64(cluster.Quorate))
|
||||
c.clusterMode.With(l).Set(cluster.GetClusterModeNumeric())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func NewPveSubscriptionCollector(apiClient *proxmox.PveApiClient, registry *TTLR
|
||||
c.status = NewTTLGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "pve_node_subscription_status",
|
||||
Help: "Node subscription status.",
|
||||
Help: "Node subscription status (0 = not found, 1 = active, 2 = expired or otherwise unusable).",
|
||||
},
|
||||
[]string{"cluster", "node"},
|
||||
5*time.Minute,
|
||||
@@ -111,7 +111,7 @@ func (c *PveSubscriptionCollector) CollectMetrics() error {
|
||||
c.info.With(subsLabels).Set(1)
|
||||
|
||||
// Subscription state.
|
||||
c.status.With(labels).Set(subscription.GetActiveNumeric())
|
||||
c.status.With(labels).Set(subscription.GetStatusNumeric())
|
||||
|
||||
// Subscription sockets count.
|
||||
c.sockets.With(labels).Set(float64(subscription.Sockets))
|
||||
|
||||
+20
-6
@@ -430,13 +430,18 @@ func (r *PveSdnResource) GetStatusNumeric() float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetActiveNumeric returns the numeric state of a subscription.
|
||||
// Returns 1 if the subscription status is "active", otherwise returns 0.
|
||||
func (r *PveSubscription) GetActiveNumeric() float64 {
|
||||
if r.Status == "active" {
|
||||
return 1
|
||||
}
|
||||
// GetStatusNumeric returns the numeric state of a subscription.
|
||||
// A missing subscription is 0, an active subscription is 1, and an expired
|
||||
// or otherwise unusable subscription is 2.
|
||||
func (r *PveSubscription) GetStatusNumeric() float64 {
|
||||
switch r.Status {
|
||||
case "notfound":
|
||||
return 0
|
||||
case "active":
|
||||
return 1
|
||||
default:
|
||||
return 2
|
||||
}
|
||||
}
|
||||
|
||||
// GetSmartPassedState returns the numeric health state of a disk.
|
||||
@@ -486,6 +491,15 @@ func (r *PveQemuStatus) IsRunning() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// GetClusterModeNumeric returns whether the PVE installation is configured as a cluster.
|
||||
// The cluster status API includes an object with type "cluster" only in cluster mode.
|
||||
func (r *PveClusterStatus) GetClusterModeNumeric() float64 {
|
||||
if r.Type == "cluster" {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetClusterName returns name of cluster for labeling purposes.
|
||||
// If there is no cluster then return standalone node with node name. Otherwise, it returns cluster name.
|
||||
func (r *PveClusterStatus) GetClusterName() string {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package proxmox
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestPveClusterStatusGetClusterModeNumeric(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
status PveClusterStatus
|
||||
want float64
|
||||
}{
|
||||
{
|
||||
name: "cluster mode",
|
||||
status: PveClusterStatus{Type: "cluster"},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "standalone node",
|
||||
status: PveClusterStatus{},
|
||||
want: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.status.GetClusterModeNumeric(); got != tt.want {
|
||||
t.Fatalf("GetClusterModeNumeric() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPveSubscriptionGetStatusNumeric(t *testing.T) {
|
||||
tests := []struct {
|
||||
status string
|
||||
want float64
|
||||
}{
|
||||
{status: "notfound", want: 0},
|
||||
{status: "active", want: 1},
|
||||
{status: "expired", want: 2},
|
||||
{status: "invalid", want: 2},
|
||||
{status: "suspended", want: 2},
|
||||
{status: "new", want: 2},
|
||||
{status: "unknown", want: 2},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.status, func(t *testing.T) {
|
||||
subscription := PveSubscription{Status: tt.status}
|
||||
if got := subscription.GetStatusNumeric(); got != tt.want {
|
||||
t.Fatalf("GetStatusNumeric() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user