From 528c5612e330fbfb34bc546e734f0f0a0599f104 Mon Sep 17 00:00:00 2001 From: Laurent Corbes Date: Mon, 24 Jun 2024 18:04:15 +0200 Subject: [PATCH 1/3] feat: Add version metric Signed-off-by: Laurent Corbes --- main.go | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 26db73b..82b8edc 100644 --- a/main.go +++ b/main.go @@ -20,6 +20,7 @@ import ( ) const promNamespace = "pbs" +const versionApi = "/api2/json/version" const datastoreUsageApi = "/api2/json/status/datastore-usage" const datastoreApi = "/api2/json/admin/datastore" const nodeApi = "/api2/json/nodes" @@ -65,6 +66,11 @@ var ( "Was the last query of PBS successful.", nil, nil, ) + version = prometheus.NewDesc( + prometheus.BuildFQName(promNamespace, "", "version"), + "Version of the PBS installation.", + []string{"version"}, nil, + ) available = prometheus.NewDesc( prometheus.BuildFQName(promNamespace, "", "available"), "The available bytes of the underlying storage.", @@ -177,6 +183,14 @@ var ( ) ) +type VersionResponse struct { + Data struct { + Release string `json:"release"` + Repoid string `json:"repoid"` + Version string `json:"version"` + } `json:"data"` +} + type DatastoreResponse struct { Data []struct { Avail int64 `json:"avail"` @@ -268,6 +282,7 @@ func NewExporter(endpoint string, username string, apitoken string, apitokenname func (e *Exporter) Describe(ch chan<- *prometheus.Desc) { ch <- up + ch <- version ch <- available ch <- size ch <- used @@ -308,6 +323,13 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) { } func (e *Exporter) collectFromAPI(ch chan<- prometheus.Metric) error { + + // get version + err := e.getVersion(ch) + if err != nil { + return err + } + // get datastores req, err := http.NewRequest("GET", e.endpoint+datastoreUsageApi, nil) if err != nil { @@ -320,7 +342,7 @@ func (e *Exporter) collectFromAPI(ch chan<- prometheus.Metric) error { // debug if *loglevel == "debug" { log.Printf("DEBUG: Request URL: %s", req.URL) - //log.Printf("DEBUG: Request Header: %s", vmID) + // log.Printf("DEBUG: Request Header: %s", vmID) } // make request and show output @@ -372,6 +394,61 @@ func (e *Exporter) collectFromAPI(ch chan<- prometheus.Metric) error { return nil } +func (e *Exporter) getVersion(ch chan<- prometheus.Metric) error { + // get version + req, err := http.NewRequest("GET", e.endpoint+versionApi, nil) + if err != nil { + return err + } + + // add Authorization header + req.Header.Set("Authorization", e.authorizationHeader) + + // debug + if *loglevel == "debug" { + log.Printf("DEBUG: Request URL: %s", req.URL) + // log.Printf("DEBUG: Request Header: %s", vmID) + } + + // make request and show output + resp, err := client.Do(req) + if err != nil { + return err + } + + body, err := io.ReadAll(resp.Body) + if err := resp.Body.Close(); err != nil { + log.Printf("Error closing response body: %v", err) + } + if err != nil { + return err + } + + // debug + if *loglevel == "debug" { + log.Printf("DEBUG: Status code %d returned from endpoint: %s", resp.StatusCode, e.endpoint) + //log.Printf("DEBUG: Response body: %s", string(body)) + } + + // check if status code is 200 + if resp.StatusCode != 200 { + return fmt.Errorf("ERROR: Status code %d returned from endpoint: %s", resp.StatusCode, e.endpoint) + } + + // parse json + var response VersionResponse + err = json.Unmarshal(body, &response) + if err != nil { + return err + } + + ch <- prometheus.MustNewConstMetric( + version, prometheus.GaugeValue, 1, response.Data.Version, + ) + + return nil +} + func (e *Exporter) getNodeMetrics(ch chan<- prometheus.Metric) error { // NOTE: According to the api documentation, we have to provide the node name (won't work with the node ip), // but it seems to work with any name, so we just use "localhost" here. From 5ac4f6c5e83cf94e63bc4db02ad1f2cdf366b87c Mon Sep 17 00:00:00 2001 From: Laurent Corbes Date: Tue, 25 Jun 2024 10:41:10 +0200 Subject: [PATCH 2/3] feat: Add repoid and release to version metric Signed-off-by: Laurent Corbes --- main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 82b8edc..7f661a9 100644 --- a/main.go +++ b/main.go @@ -69,7 +69,7 @@ var ( version = prometheus.NewDesc( prometheus.BuildFQName(promNamespace, "", "version"), "Version of the PBS installation.", - []string{"version"}, nil, + []string{"version", "repoid", "release"}, nil, ) available = prometheus.NewDesc( prometheus.BuildFQName(promNamespace, "", "available"), @@ -443,7 +443,7 @@ func (e *Exporter) getVersion(ch chan<- prometheus.Metric) error { } ch <- prometheus.MustNewConstMetric( - version, prometheus.GaugeValue, 1, response.Data.Version, + version, prometheus.GaugeValue, 1, response.Data.Version, response.Data.Repoid, response.Data.Release, ) return nil From 23a5ff84385badee7f09cdc16865098826d54df2 Mon Sep 17 00:00:00 2001 From: Laurent Corbes Date: Tue, 25 Jun 2024 10:43:12 +0200 Subject: [PATCH 3/3] chore: Add version metric to README Signed-off-by: Laurent Corbes --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0a4aa18..d41c9d7 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Metrics are retrieved using the [Proxmox Backup Server API](https://pbs.proxmox. | Metric | Meaning | Labels | | ------------------------------ | ------------------------------------------------------- | -------------------------------------------- | | pbs_up | Was the last query of Proxmox Backup Server successful? | | +| pbs_version | Version of Proxmox Backup Server | `version`, `repoid`, `release` | | pbs_available | The available bytes of the underlying storage. | `datastore` | | pbs_size | The size of the underlying storage in bytes. | `datastore` | | pbs_used | The used bytes of the underlying storage. | `datastore` |