Skip to content

Commit

Permalink
Merge pull request #31 from enix/main
Browse files Browse the repository at this point in the history
feat: Add version metric
  • Loading branch information
janfuhrer authored Jun 25, 2024
2 parents ca1fc10 + 23a5ff8 commit c25dbc4
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` |
Expand Down
79 changes: 78 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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", "repoid", "release"}, nil,
)
available = prometheus.NewDesc(
prometheus.BuildFQName(promNamespace, "", "available"),
"The available bytes of the underlying storage.",
Expand Down Expand Up @@ -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"`
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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, response.Data.Repoid, response.Data.Release,
)

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.
Expand Down

0 comments on commit c25dbc4

Please sign in to comment.