VictoriaMetrics/lib/promscrape/discovery/vultr/vultr.go
Zhu Jiekun 17e3d019d2
feature: [vmagent] Add service discovery support for Vultr (#6068)
### Describe Your Changes
related issue:
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6041

#### Added
- Added service discovery support for Vultr.

#### Docs
- `CHANGELOG.md`, `sd_configs.md`, `vmagent.md` are updated.

#### Note
- Useful links: 
- Vultr API:
https://www.vultr.com/api/#tag/instances/operation/list-instances
    - Vultr client SDK: https://github.com/vultr/govultr
- Prometheus SD:
https://github.com/prometheus/prometheus/tree/main/discovery/vultr

---
### Checklist

The following checks are mandatory:

- [X] I have read the [Contributing
Guidelines](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/CONTRIBUTING.md)
- [x] All commits are signed and include `Signed-off-by` line. Use `git
commit -s` to include `Signed-off-by` your commits. See this
[doc](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) about
how to sign your commits.
- [x] Tests are passing locally. Use `make test` to run all tests
locally.
- [x] Linting is passing locally. Use `make check-all` to run all
linters locally.

Further checks are optional for External Contributions:

- [X] Include a link to the GitHub issue in the commit message, if issue
exists.
- [x] Mention the change in the
[Changelog](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/docs/CHANGELOG.md).
Explain what has changed and why. If there is a related issue or
documentation change - link them as well.

  Tips for writing a good changelog message::

* Write a human-readable changelog message that describes the problem
and solution.
* Include a link to the issue or pull request in your changelog message.
* Use specific language identifying the fix, such as an error message,
metric name, or flag name.
* Provide a link to the relevant documentation for any new features you
add or modify.

- [ ] After your pull request is merged, please add a message to the
issue with instructions for how to test the fix or try the feature you
added. Here is an
[example](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4048#issuecomment-1546453726)
- [x] Do not close the original issue before the change is released.
Please note, in some cases Github can automatically close the issue once
PR is merged. Re-open the issue in such case.
- [x] If the change somehow affects public interfaces (a new flag was
added or updated, or some behavior has changed) - add the corresponding
change to documentation.

Signed-off-by: Jiekun <jiekun.dev@gmail.com>
2024-05-08 10:01:48 +02:00

106 lines
4.1 KiB
Go

package vultr
import (
"flag"
"fmt"
"strconv"
"strings"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/proxy"
)
const (
separator = ","
)
// SDCheckInterval defines interval for docker targets refresh.
var SDCheckInterval = flag.Duration("promscrape.vultrSDCheckInterval", 30*time.Second, "Interval for checking for changes in Vultr. "+
"This works only if vultr_sd_configs is configured in '-promscrape.config' file. "+
"See https://docs.victoriametrics.com/sd_configs.html#vultr_sd_configs for details")
// SDConfig represents service discovery config for Vultr.
// See: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#vultr_sd_config
// Additional query params are supported, while Prometheus only supports `Port` and HTTP auth.
type SDConfig struct {
// API query params for filtering. All of them are optional.
// See: https://www.vultr.com/api/#tag/instances/operation/list-instances
Label string `yaml:"label,omitempty"`
MainIP string `yaml:"main_ip,omitempty"`
Region string `yaml:"region,omitempty"`
FirewallGroupID string `yaml:"firewall_group_id,omitempty"`
Hostname string `yaml:"hostname,omitempty"`
// The port to scrape metrics from. Default 80.
Port int `yaml:"port"`
// General HTTP / Auth configs.
HTTPClientConfig promauth.HTTPClientConfig `yaml:",inline"`
ProxyURL *proxy.URL `yaml:"proxy_url,omitempty"`
ProxyClientConfig promauth.ProxyClientConfig `yaml:",inline"`
// refresh_interval is obtained from `-promscrape.vultrSDCheckInterval` command-line option.
}
var configMap = discoveryutils.NewConfigMap()
// GetLabels returns gce labels according to sdc.
func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutils.Labels, error) {
ac, err := getAPIConfig(sdc, baseDir)
if err != nil {
return nil, fmt.Errorf("cannot get API config: %w", err)
}
instances, err := getInstances(ac)
if err != nil {
return nil, err
}
return getInstanceLabels(instances, ac.port), nil
}
// MustStop stops further usage for sdc.
func (sdc *SDConfig) MustStop() {
configMap.Delete(sdc)
}
// getInstanceLabels returns labels for vultr instances obtained from the given cfg
func getInstanceLabels(instances []Instance, port int) []*promutils.Labels {
ms := make([]*promutils.Labels, 0, len(instances))
for _, instance := range instances {
m := promutils.NewLabels(18)
m.Add("__address__", discoveryutils.JoinHostPort(instance.MainIP, port))
m.Add("__meta_vultr_instance_id", instance.ID)
m.Add("__meta_vultr_instance_label", instance.Label)
m.Add("__meta_vultr_instance_os", instance.Os)
m.Add("__meta_vultr_instance_os_id", strconv.Itoa(instance.OsID))
m.Add("__meta_vultr_instance_region", instance.Region)
m.Add("__meta_vultr_instance_plan", instance.Plan)
m.Add("__meta_vultr_instance_main_ip", instance.MainIP)
m.Add("__meta_vultr_instance_internal_ip", instance.InternalIP)
m.Add("__meta_vultr_instance_main_ipv6", instance.V6MainIP)
m.Add("__meta_vultr_instance_hostname", instance.Hostname)
m.Add("__meta_vultr_instance_server_status", instance.ServerStatus)
m.Add("__meta_vultr_instance_vcpu_count", strconv.Itoa(instance.VCPUCount))
m.Add("__meta_vultr_instance_ram_mb", strconv.Itoa(instance.RAM))
m.Add("__meta_vultr_instance_allowed_bandwidth_gb", strconv.Itoa(instance.AllowedBandwidth))
m.Add("__meta_vultr_instance_disk_gb", strconv.Itoa(instance.Disk))
// We surround the separated list with the separator as well. This way regular expressions
// in relabeling rules don't have to consider feature positions.
if len(instance.Features) > 0 {
features := separator + strings.Join(instance.Features, separator) + separator
m.Add("__meta_vultr_instance_features", features)
}
if len(instance.Tags) > 0 {
tags := separator + strings.Join(instance.Tags, separator) + separator
m.Add("__meta_vultr_instance_tags", tags)
}
ms = append(ms, m)
}
return ms
}