VictoriaMetrics/lib/promscrape/discovery/puppetdb/resource.go
Zhu Jiekun f06c7e99fe
lib/promscrape: adds support for PuppetDB service discovery
This commit adds support for
[PuppetDB](https://www.puppet.com/docs/puppetdb/8/overview.html) service
discovery to the `vmagent` and `victoria-metrics-single` components.

Related issue https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5744
2024-10-27 20:38:34 +01:00

152 lines
4.1 KiB
Go

package puppetdb
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
const (
separator = ","
)
type resource struct {
Certname string `json:"certname"`
Resource string `json:"resource"`
Type string `json:"type"`
Title string `json:"title"`
Exported bool `json:"exported"`
Tags []string `json:"tags"`
File string `json:"file"`
Environment string `json:"environment"`
Parameters parameters `json:"parameters"`
}
type parameters map[string]interface{}
// addToLabels add Parameters map to existing labels.
// See: https://github.com/prometheus/prometheus/blob/685493187ec5f5734777769f595cf8418d49900d/discovery/puppetdb/resources.go#L39
func (p *parameters) addToLabels(keyPrefix string, m *promutils.Labels) {
if p == nil {
return
}
for k, v := range *p {
var labelValue string
switch value := v.(type) {
case string:
labelValue = value
case bool:
labelValue = strconv.FormatBool(value)
case int64:
labelValue = strconv.FormatInt(value, 10)
case float64:
labelValue = strconv.FormatFloat(value, 'g', -1, 64)
case []string:
labelValue = separator + strings.Join(value, separator) + separator
case []interface{}:
if len(value) == 0 {
continue
}
values := make([]string, len(value))
for i, v := range value {
switch value := v.(type) {
case string:
values[i] = value
case bool:
values[i] = strconv.FormatBool(value)
case int64:
values[i] = strconv.FormatInt(value, 10)
case float64:
values[i] = strconv.FormatFloat(value, 'g', -1, 64)
case []string:
values[i] = separator + strings.Join(value, separator) + separator
}
}
labelValue = strings.Join(values, separator)
case map[string]interface{}:
subParameter := parameters(value)
subParameter.addToLabels(keyPrefix+discoveryutils.SanitizeLabelName(k+"_"), m)
default:
continue
}
if labelValue == "" {
continue
}
name := discoveryutils.SanitizeLabelName(k)
m.Add(keyPrefix+name, labelValue)
}
}
func getResourceList(cfg *apiConfig) ([]resource, error) {
body := struct {
Query string `json:"query"`
}{cfg.query}
bodyBytes, err := json.Marshal(body)
if err != nil {
return nil, err
}
modifyRequestFunc := func(request *http.Request) {
request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
request.Header.Set("Accept", "application/json")
request.Header.Set("Content-Type", "application/json")
request.Method = http.MethodPost
}
// https://www.puppet.com/docs/puppetdb/8/api/query/v4/overview#pdbqueryv4
resp, err := cfg.client.GetAPIResponseWithReqParams("/pdb/query/v4", modifyRequestFunc)
if err != nil {
return nil, err
}
var resources []resource
if err = json.Unmarshal(resp, &resources); err != nil {
return nil, err
}
return resources, nil
}
func getResourceLabels(resources []resource, cfg *apiConfig) []*promutils.Labels {
ms := make([]*promutils.Labels, 0, len(resources))
for _, res := range resources {
m := promutils.NewLabels(18)
m.Add("__address__", discoveryutils.JoinHostPort(res.Certname, cfg.port))
m.Add("__meta_puppetdb_certname", res.Certname)
m.Add("__meta_puppetdb_environment", res.Environment)
m.Add("__meta_puppetdb_exported", fmt.Sprintf("%t", res.Exported))
m.Add("__meta_puppetdb_file", res.File)
m.Add("__meta_puppetdb_query", cfg.query)
m.Add("__meta_puppetdb_resource", res.Resource)
m.Add("__meta_puppetdb_title", res.Title)
m.Add("__meta_puppetdb_type", res.Type)
if len(res.Tags) > 0 {
//discoveryutils.AddTagsToLabels(m, resource.Tags, "__meta_puppetdb_tags", separator)
m.Add("__meta_puppetdb_tags", separator+strings.Join(res.Tags, separator)+separator)
}
// Parameters are not included by default. This should only be enabled
// on select resources as it might expose secrets on the Prometheus UI
// for certain resources.
if cfg.includeParameters {
res.Parameters.addToLabels("__meta_puppetdb_parameter_", m)
}
ms = append(ms, m)
}
return ms
}