2 Commits
Author SHA1 Message Date
lostakj e5a5e6416b Added cluster mode metric
Build Docker image on push / docker (push) Successful in 22s
Build and push Docker image on tag / docker (push) Successful in 22s
2026-08-17 21:29:09 +02:00
lostakj c4287c37bc Aktualizovat README.md
Build Docker image on push / docker (push) Successful in 39s
2026-04-10 09:34:29 +00:00
4 changed files with 61 additions and 6 deletions
+6 -3
View File
@@ -58,12 +58,15 @@ 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.
## 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 +76,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.
@@ -101,4 +104,4 @@ Contributions are welcome! Please open an issue or submit a pull request if you
## Support
If you encounter any issues or have questions, please open an issue on the project's GitHub repository.
If you encounter any issues or have questions, please open an issue on the project's GitHub repository.
+16 -3
View File
@@ -12,8 +12,9 @@ type PveClusterStateCollector struct {
apiClient *proxmox.PveApiClient // PVE API client instance.
registry *TTLRegistry // TTL metrics registry.
nodes *TTLGaugeVec // Count of nodes prometheus gauge.
quorate *TTLGaugeVec // Cluster quorum state prometheus gauge.
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
}
+9
View File
@@ -486,6 +486,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 {
+30
View File
@@ -0,0 +1,30 @@
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)
}
})
}
}