mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-24 05:04:05 -08:00
vultr integration
Signed-off-by: David Dymko <dymkod@gmail.com>
This commit is contained in:
parent
d11c418102
commit
3ef153b00c
|
@ -51,6 +51,7 @@ import (
|
|||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
"github.com/prometheus/prometheus/discovery/triton"
|
||||
"github.com/prometheus/prometheus/discovery/uyuni"
|
||||
"github.com/prometheus/prometheus/discovery/vultr"
|
||||
"github.com/prometheus/prometheus/discovery/xds"
|
||||
"github.com/prometheus/prometheus/discovery/zookeeper"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
|
@ -1020,6 +1021,32 @@ var expectedConf = &Config{
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
JobName: "vultr",
|
||||
|
||||
HonorTimestamps: true,
|
||||
ScrapeInterval: model.Duration(15 * time.Second),
|
||||
ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
|
||||
|
||||
MetricsPath: DefaultScrapeConfig.MetricsPath,
|
||||
Scheme: DefaultScrapeConfig.Scheme,
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
|
||||
ServiceDiscoveryConfigs: discovery.Configs{
|
||||
&vultr.SDConfig{
|
||||
HTTPClientConfig: config.HTTPClientConfig{
|
||||
Authorization: &config.Authorization{
|
||||
Type: "Bearer",
|
||||
Credentials: "abcdef",
|
||||
},
|
||||
FollowRedirects: true,
|
||||
EnableHTTP2: true,
|
||||
},
|
||||
Port: 80,
|
||||
RefreshInterval: model.Duration(60 * time.Second),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AlertingConfig: AlertingConfig{
|
||||
AlertmanagerConfigs: []*AlertmanagerConfig{
|
||||
|
@ -1117,7 +1144,7 @@ func TestElideSecrets(t *testing.T) {
|
|||
yamlConfig := string(config)
|
||||
|
||||
matches := secretRe.FindAllStringIndex(yamlConfig, -1)
|
||||
require.Equal(t, 17, len(matches), "wrong number of secret matches found")
|
||||
require.Equal(t, 18, len(matches), "wrong number of secret matches found")
|
||||
require.NotContains(t, yamlConfig, "mysecret",
|
||||
"yaml marshal reveals authentication credentials.")
|
||||
}
|
||||
|
|
5
config/testdata/conf.good.yml
vendored
5
config/testdata/conf.good.yml
vendored
|
@ -373,6 +373,11 @@ scrape_configs:
|
|||
authorization:
|
||||
credentials: abcdef
|
||||
|
||||
- job_name: vultr
|
||||
vultr_sd_configs:
|
||||
- authorization:
|
||||
credentials: abcdef
|
||||
|
||||
alerting:
|
||||
alertmanagers:
|
||||
- scheme: https
|
||||
|
|
|
@ -36,6 +36,7 @@ import (
|
|||
_ "github.com/prometheus/prometheus/discovery/scaleway" // register scaleway
|
||||
_ "github.com/prometheus/prometheus/discovery/triton" // register triton
|
||||
_ "github.com/prometheus/prometheus/discovery/uyuni" // register uyuni
|
||||
_ "github.com/prometheus/prometheus/discovery/vultr" // register vultr
|
||||
_ "github.com/prometheus/prometheus/discovery/xds" // register xds
|
||||
_ "github.com/prometheus/prometheus/discovery/zookeeper" // register zookeeper
|
||||
)
|
||||
|
|
170
discovery/vultr/mock_test.go
Normal file
170
discovery/vultr/mock_test.go
Normal file
|
@ -0,0 +1,170 @@
|
|||
// Copyright 2022 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package vultr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// SDMock is the interface for the Vultr mock
|
||||
type SDMock struct {
|
||||
t *testing.T
|
||||
Server *httptest.Server
|
||||
Mux *http.ServeMux
|
||||
}
|
||||
|
||||
// NewSDMock returns a new SDMock.
|
||||
func NewSDMock(t *testing.T) *SDMock {
|
||||
return &SDMock{
|
||||
t: t,
|
||||
}
|
||||
}
|
||||
|
||||
// Endpoint returns the URI to the mock server
|
||||
func (m *SDMock) Endpoint() string {
|
||||
return m.Server.URL + "/"
|
||||
}
|
||||
|
||||
// Setup creates the mock server
|
||||
func (m *SDMock) Setup() {
|
||||
m.Mux = http.NewServeMux()
|
||||
m.Server = httptest.NewServer(m.Mux)
|
||||
}
|
||||
|
||||
// ShutdownServer creates the mock server
|
||||
func (m *SDMock) ShutdownServer() {
|
||||
m.Server.Close()
|
||||
}
|
||||
|
||||
const APIKey = "ABCBTDG35OTGH2UKCC3S6CNMDUPCN3ZWSGFQ"
|
||||
|
||||
// HandleInstanceList mocks vultr instances list.
|
||||
func (m *SDMock) HandleInstanceList() {
|
||||
m.Mux.HandleFunc("/v2/instances", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", APIKey) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Add("content-type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
fmt.Fprint(w, `
|
||||
{
|
||||
"instances": [
|
||||
{
|
||||
"id": "dbdbd38c-9884-4c92-95fe-899e50dee717",
|
||||
"os": "Marketplace",
|
||||
"ram": 4096,
|
||||
"disk": 128,
|
||||
"main_ip": "149.28.234.27",
|
||||
"vcpu_count": 2,
|
||||
"region": "ewr",
|
||||
"plan": "vhf-2c-4gb",
|
||||
"date_created": "2022-03-10T02:25:30+00:00",
|
||||
"status": "active",
|
||||
"allowed_bandwidth": 3000,
|
||||
"netmask_v4": "255.255.254.0",
|
||||
"gateway_v4": "149.28.234.1",
|
||||
"power_status": "running",
|
||||
"server_status": "ok",
|
||||
"v6_network": "",
|
||||
"v6_main_ip": "",
|
||||
"v6_network_size": 0,
|
||||
"label": "np-2-eae38a19b0f3",
|
||||
"internal_ip": "10.1.96.5",
|
||||
"kvm": "https://my.vultr.com/subs/vps/novnc/api.php?data=djJ8Q2k2NlVpNUlZNE5kM3NZMWdBNzFKUkVadDBDU3ItTEJ8-yNWBdMn1AWPqX-EnpTVbA1qBeP0txBZbahSOh3UtHIL2p0fZKEdFJwFNjWtvBKC9BGvJkoJdWBoo7hF-6RzavdUKPD3KIU5xD_T6keV8X-PPukPgXMuSUaAqurAuJvwAWXcTcodBjaIH961xgbvfkFyqVl0ZgHf3ErZQE-EmpZ0Jc3uF1DO2McJ4UL8KUvHLwa-ZDUZ_AtWJjQWsjNkxjvOiA",
|
||||
"hostname": "np-2-eae38a19b0f3",
|
||||
"os_id": 426,
|
||||
"app_id": 0,
|
||||
"image_id": "vke-worker",
|
||||
"firewall_group_id": "",
|
||||
"features": ["backups"],
|
||||
"tags": ["tag1", "tag2", "tag3"]
|
||||
},
|
||||
{
|
||||
"id": "fccb117c-62f7-4b17-995d-a8e56dd30b33",
|
||||
"os": "Marketplace",
|
||||
"ram": 4096,
|
||||
"disk": 128,
|
||||
"main_ip": "45.63.1.222",
|
||||
"vcpu_count": 2,
|
||||
"region": "ewr",
|
||||
"plan": "vhf-2c-4gb",
|
||||
"date_created": "2022-03-10T02:25:32+00:00",
|
||||
"status": "active",
|
||||
"allowed_bandwidth": 3000,
|
||||
"netmask_v4": "255.255.254.0",
|
||||
"gateway_v4": "45.63.0.1",
|
||||
"power_status": "running",
|
||||
"server_status": "ok",
|
||||
"v6_network": "",
|
||||
"v6_main_ip": "",
|
||||
"v6_network_size": 0,
|
||||
"label": "np-2-fd0714b5fe42",
|
||||
"internal_ip": "10.1.96.6",
|
||||
"kvm": "https://my.vultr.com/subs/vps/novnc/api.php?data=djJ8R0tzbmI0VWVfSDR6VE51Q0FGUTBCamwyTFNzZDNkVTF8Zwm93t6L2BLTYSNmM0g0Ppf43r71aIbqLiJCx6_1NuCugUqIKz8POshH91vi6XXDorpb3hYTk8RrJWQbaFMak7XbbfMObzsrFxKAQUVGfbjTBIHCKftxNIXeQOp1fEIDa3p-vkfSxEpx6ZX8nChGYYSVuOjS1twV6oI_IKtHXKdFJiVFz0Unay_K3HuXW_H2wrYSjmAChloR-eA1jSmBXLccJQ",
|
||||
"hostname": "np-2-fd0714b5fe42",
|
||||
"os_id": 426,
|
||||
"app_id": 0,
|
||||
"image_id": "vke-worker",
|
||||
"firewall_group_id": "",
|
||||
"features": [],
|
||||
"tags": []
|
||||
},
|
||||
{
|
||||
"id": "c4e58767-f61b-4c5e-9bce-43761cc04868",
|
||||
"os": "Marketplace",
|
||||
"ram": 4096,
|
||||
"disk": 128,
|
||||
"main_ip": "149.28.237.151",
|
||||
"vcpu_count": 2,
|
||||
"region": "ewr",
|
||||
"plan": "vhf-2c-4gb",
|
||||
"date_created": "2022-03-10T02:25:33+00:00",
|
||||
"status": "active",
|
||||
"allowed_bandwidth": 3000,
|
||||
"netmask_v4": "255.255.254.0",
|
||||
"gateway_v4": "149.28.236.1",
|
||||
"power_status": "running",
|
||||
"server_status": "ok",
|
||||
"v6_network": "",
|
||||
"v6_main_ip": "",
|
||||
"v6_network_size": 0,
|
||||
"label": "np-2-d04e7829fa43",
|
||||
"internal_ip": "10.1.96.7",
|
||||
"kvm": "https://my.vultr.com/subs/vps/novnc/api.php?data=djJ8NFEzbFZmV2hOUWNrc2R4bndnckhFQTJ3ME1yWmxVeW98P-p-KeyNtP73wzVvuWZSOrV5PvQDiBmYyB3cp99btIy5nczmvX8DOGSChbEldk3idKNdFLQMIieWnpR5xU5K-dMYlL6n6oYv2u-rh8zxS6-8hQsSbL2OsoywNPoLpQ3xPkT9Rb-yPrZX4fDLbt8yPVKDHqHO0GB-TxVPemueovfkkUZMXSraAXgHtl1YgK2uLMQf1WBFVzgwnQ7MYcfMGGYFQw",
|
||||
"hostname": "np-2-d04e7829fa43",
|
||||
"os_id": 426,
|
||||
"app_id": 0,
|
||||
"image_id": "vke-worker",
|
||||
"firewall_group_id": "",
|
||||
"features": [],
|
||||
"tags": []
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"total": 3,
|
||||
"links": {
|
||||
"next": "",
|
||||
"prev": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
})
|
||||
}
|
212
discovery/vultr/vultr.go
Normal file
212
discovery/vultr/vultr.go
Normal file
|
@ -0,0 +1,212 @@
|
|||
// Copyright 2022 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package vultr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/version"
|
||||
"github.com/vultr/govultr/v2"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery"
|
||||
"github.com/prometheus/prometheus/discovery/refresh"
|
||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
)
|
||||
|
||||
const (
|
||||
vultrInstanceLabel = model.MetaLabelPrefix + "vultr_instance_"
|
||||
vultrInstanceLabelID = vultrInstanceLabel + "id"
|
||||
vultrInstanceLabelLabel = vultrInstanceLabel + "label"
|
||||
vultrInstanceLabelOS = vultrInstanceLabel + "os"
|
||||
vultrInstanceLabelOSID = vultrInstanceLabel + "os_id"
|
||||
vultrInstanceLabelRegion = vultrInstanceLabel + "region"
|
||||
vultrInstanceLabelPlan = vultrInstanceLabel + "plan"
|
||||
vultrInstanceLabelMainIP = vultrInstanceLabel + "main_ip"
|
||||
vultrInstanceLabelMainIPV6 = vultrInstanceLabel + "main_ipv6"
|
||||
vultrInstanceLabelInternalIP = vultrInstanceLabel + "internal_ip"
|
||||
vultrInstanceLabelFeatures = vultrInstanceLabel + "features"
|
||||
vultrInstanceLabelTags = vultrInstanceLabel + "tags"
|
||||
vultrInstanceLabelHostname = vultrInstanceLabel + "hostname"
|
||||
vultrInstanceLabelServerStatus = vultrInstanceLabel + "server_status"
|
||||
vultrInstanceLabelVCPU = vultrInstanceLabel + "vcpu_count"
|
||||
vultrInstanceLabelMemory = vultrInstanceLabel + "ram_bytes"
|
||||
vultrInstanceLabelBandwidth = vultrInstanceLabel + "allowed_bandwidth_gb"
|
||||
vultrInstanceLabelDisk = vultrInstanceLabel + "disk_gb"
|
||||
separator = ","
|
||||
)
|
||||
|
||||
// DefaultSDConfig is the default Vultr SD configuration.
|
||||
var DefaultSDConfig = SDConfig{
|
||||
Port: 80,
|
||||
RefreshInterval: model.Duration(60 * time.Second),
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
}
|
||||
|
||||
func init() {
|
||||
discovery.RegisterConfig(&SDConfig{})
|
||||
}
|
||||
|
||||
type SDConfig struct {
|
||||
HTTPClientConfig config.HTTPClientConfig `yaml:",inline"`
|
||||
|
||||
RefreshInterval model.Duration `yaml:"refresh_interval"`
|
||||
Port int `yaml:"port"`
|
||||
}
|
||||
|
||||
// Name returns the name of the Config.
|
||||
func (*SDConfig) Name() string { return "vultr" }
|
||||
|
||||
// NewDiscoverer returns a Discoverer for the Config.
|
||||
func (c *SDConfig) NewDiscoverer(opts discovery.DiscovererOptions) (discovery.Discoverer, error) {
|
||||
return NewDiscovery(c, opts.Logger)
|
||||
}
|
||||
|
||||
// SetDirectory joins any relative file paths with dir.
|
||||
func (c *SDConfig) SetDirectory(dir string) {
|
||||
c.HTTPClientConfig.SetDirectory(dir)
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultSDConfig
|
||||
type plain SDConfig
|
||||
if err := unmarshal((*plain)(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.HTTPClientConfig.Validate()
|
||||
}
|
||||
|
||||
// Discovery periodically performs Vultr requests. It implements
|
||||
// the Discoverer interface.
|
||||
type Discovery struct {
|
||||
*refresh.Discovery
|
||||
client *govultr.Client
|
||||
port int
|
||||
}
|
||||
|
||||
// NewDiscovery returns a new Discovery which periodically refreshes its targets.
|
||||
func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) {
|
||||
d := &Discovery{
|
||||
port: conf.Port,
|
||||
}
|
||||
|
||||
rt, err := config.NewRoundTripperFromConfig(conf.HTTPClientConfig, "vultr_sd")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.client = govultr.NewClient(&http.Client{
|
||||
Transport: rt,
|
||||
Timeout: time.Duration(conf.RefreshInterval),
|
||||
})
|
||||
|
||||
d.client.SetUserAgent(fmt.Sprintf("Prometheus/%s", version.Version))
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error setting up vultr agent: %w", err)
|
||||
}
|
||||
|
||||
d.Discovery = refresh.NewDiscovery(
|
||||
logger,
|
||||
"vultr",
|
||||
time.Duration(conf.RefreshInterval),
|
||||
d.refresh,
|
||||
)
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
||||
tg := &targetgroup.Group{
|
||||
Source: "Vultr",
|
||||
}
|
||||
|
||||
instances, err := d.listInstances(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, instance := range instances {
|
||||
labels := model.LabelSet{
|
||||
vultrInstanceLabelID: model.LabelValue(instance.ID),
|
||||
vultrInstanceLabelLabel: model.LabelValue(instance.Label),
|
||||
vultrInstanceLabelOS: model.LabelValue(instance.Os),
|
||||
vultrInstanceLabelOSID: model.LabelValue(strconv.Itoa(instance.OsID)),
|
||||
vultrInstanceLabelRegion: model.LabelValue(instance.Region),
|
||||
vultrInstanceLabelPlan: model.LabelValue(instance.Plan),
|
||||
vultrInstanceLabelVCPU: model.LabelValue(strconv.Itoa(instance.VCPUCount)),
|
||||
vultrInstanceLabelMemory: model.LabelValue(strconv.Itoa(instance.RAM)),
|
||||
vultrInstanceLabelBandwidth: model.LabelValue(strconv.Itoa(instance.AllowedBandwidth)),
|
||||
vultrInstanceLabelDisk: model.LabelValue(strconv.Itoa(instance.Disk)),
|
||||
vultrInstanceLabelMainIP: model.LabelValue(instance.MainIP),
|
||||
vultrInstanceLabelMainIPV6: model.LabelValue(instance.V6MainIP),
|
||||
vultrInstanceLabelInternalIP: model.LabelValue(instance.InternalIP),
|
||||
vultrInstanceLabelHostname: model.LabelValue(instance.Hostname),
|
||||
vultrInstanceLabelServerStatus: model.LabelValue(instance.ServerStatus),
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(instance.MainIP, strconv.FormatUint(uint64(d.port), 10))
|
||||
labels[model.AddressLabel] = model.LabelValue(addr)
|
||||
|
||||
// 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
|
||||
labels[vultrInstanceLabelFeatures] = model.LabelValue(features)
|
||||
}
|
||||
|
||||
if len(instance.Tags) > 0 {
|
||||
tags := separator + strings.Join(instance.Tags, separator) + separator
|
||||
labels[vultrInstanceLabelTags] = model.LabelValue(tags)
|
||||
}
|
||||
|
||||
tg.Targets = append(tg.Targets, labels)
|
||||
}
|
||||
|
||||
return []*targetgroup.Group{tg}, nil
|
||||
}
|
||||
|
||||
func (d *Discovery) listInstances(ctx context.Context) ([]govultr.Instance, error) {
|
||||
var instances []govultr.Instance
|
||||
|
||||
listOptions := &govultr.ListOptions{
|
||||
PerPage: 100,
|
||||
}
|
||||
|
||||
for {
|
||||
pagedInstances, meta, err := d.client.Instance.List(ctx, listOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instances = append(instances, pagedInstances...)
|
||||
|
||||
if meta.Links.Next == "" {
|
||||
break
|
||||
} else {
|
||||
listOptions.Cursor = meta.Links.Next
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return instances, nil
|
||||
}
|
128
discovery/vultr/vultr_test.go
Normal file
128
discovery/vultr/vultr_test.go
Normal file
|
@ -0,0 +1,128 @@
|
|||
// Copyright 2022 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package vultr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type VultrSDTestSuite struct {
|
||||
Mock *SDMock
|
||||
}
|
||||
|
||||
func (s *VultrSDTestSuite) TearDownSuite() {
|
||||
s.Mock.ShutdownServer()
|
||||
}
|
||||
|
||||
func (s *VultrSDTestSuite) SetupTest(t *testing.T) {
|
||||
s.Mock = NewSDMock(t)
|
||||
s.Mock.Setup()
|
||||
|
||||
s.Mock.HandleInstanceList()
|
||||
}
|
||||
|
||||
func TestVultrSDRefresh(t *testing.T) {
|
||||
sdMock := &VultrSDTestSuite{}
|
||||
sdMock.SetupTest(t)
|
||||
t.Cleanup(sdMock.TearDownSuite)
|
||||
|
||||
cfg := DefaultSDConfig
|
||||
cfg.HTTPClientConfig.BearerToken = APIKey
|
||||
d, err := NewDiscovery(&cfg, log.NewNopLogger())
|
||||
require.NoError(t, err)
|
||||
endpoint, err := url.Parse(sdMock.Mock.Endpoint())
|
||||
require.NoError(t, err)
|
||||
d.client.BaseURL = endpoint
|
||||
|
||||
ctx := context.Background()
|
||||
tgs, err := d.refresh(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(tgs))
|
||||
|
||||
tg := tgs[0]
|
||||
require.NotNil(t, tg)
|
||||
require.NotNil(t, tg.Targets)
|
||||
require.Equal(t, 3, len(tg.Targets))
|
||||
|
||||
for i, k := range []model.LabelSet{
|
||||
{
|
||||
"__address__": model.LabelValue("149.28.234.27:80"),
|
||||
"__meta_vultr_instance_id": model.LabelValue("dbdbd38c-9884-4c92-95fe-899e50dee717"),
|
||||
"__meta_vultr_instance_label": model.LabelValue("np-2-eae38a19b0f3"),
|
||||
"__meta_vultr_instance_os": model.LabelValue("Marketplace"),
|
||||
"__meta_vultr_instance_os_id": model.LabelValue("426"),
|
||||
"__meta_vultr_instance_region": model.LabelValue("ewr"),
|
||||
"__meta_vultr_instance_plan": model.LabelValue("vhf-2c-4gb"),
|
||||
"__meta_vultr_instance_main_ip": model.LabelValue("149.28.234.27"),
|
||||
"__meta_vultr_instance_internal_ip": model.LabelValue("10.1.96.5"),
|
||||
"__meta_vultr_instance_main_ipv6": model.LabelValue(""),
|
||||
"__meta_vultr_instance_features": model.LabelValue(",backups,"),
|
||||
"__meta_vultr_instance_tags": model.LabelValue(",tag1,tag2,tag3,"),
|
||||
"__meta_vultr_instance_hostname": model.LabelValue("np-2-eae38a19b0f3"),
|
||||
"__meta_vultr_instance_server_status": model.LabelValue("ok"),
|
||||
"__meta_vultr_instance_vcpu_count": model.LabelValue("2"),
|
||||
"__meta_vultr_instance_ram_bytes": model.LabelValue("4096"),
|
||||
"__meta_vultr_instance_disk_gb": model.LabelValue("128"),
|
||||
"__meta_vultr_instance_allowed_bandwidth_gb": model.LabelValue("3000"),
|
||||
},
|
||||
{
|
||||
"__address__": model.LabelValue("45.63.1.222:80"),
|
||||
"__meta_vultr_instance_id": model.LabelValue("fccb117c-62f7-4b17-995d-a8e56dd30b33"),
|
||||
"__meta_vultr_instance_label": model.LabelValue("np-2-fd0714b5fe42"),
|
||||
"__meta_vultr_instance_os": model.LabelValue("Marketplace"),
|
||||
"__meta_vultr_instance_os_id": model.LabelValue("426"),
|
||||
"__meta_vultr_instance_region": model.LabelValue("ewr"),
|
||||
"__meta_vultr_instance_plan": model.LabelValue("vhf-2c-4gb"),
|
||||
"__meta_vultr_instance_main_ip": model.LabelValue("45.63.1.222"),
|
||||
"__meta_vultr_instance_internal_ip": model.LabelValue("10.1.96.6"),
|
||||
"__meta_vultr_instance_main_ipv6": model.LabelValue(""),
|
||||
"__meta_vultr_instance_hostname": model.LabelValue("np-2-fd0714b5fe42"),
|
||||
"__meta_vultr_instance_server_status": model.LabelValue("ok"),
|
||||
"__meta_vultr_instance_vcpu_count": model.LabelValue("2"),
|
||||
"__meta_vultr_instance_ram_bytes": model.LabelValue("4096"),
|
||||
"__meta_vultr_instance_disk_gb": model.LabelValue("128"),
|
||||
"__meta_vultr_instance_allowed_bandwidth_gb": model.LabelValue("3000"),
|
||||
},
|
||||
{
|
||||
"__address__": model.LabelValue("149.28.237.151:80"),
|
||||
"__meta_vultr_instance_id": model.LabelValue("c4e58767-f61b-4c5e-9bce-43761cc04868"),
|
||||
"__meta_vultr_instance_label": model.LabelValue("np-2-d04e7829fa43"),
|
||||
"__meta_vultr_instance_os": model.LabelValue("Marketplace"),
|
||||
"__meta_vultr_instance_os_id": model.LabelValue("426"),
|
||||
"__meta_vultr_instance_region": model.LabelValue("ewr"),
|
||||
"__meta_vultr_instance_plan": model.LabelValue("vhf-2c-4gb"),
|
||||
"__meta_vultr_instance_main_ip": model.LabelValue("149.28.237.151"),
|
||||
"__meta_vultr_instance_internal_ip": model.LabelValue("10.1.96.7"),
|
||||
"__meta_vultr_instance_main_ipv6": model.LabelValue(""),
|
||||
"__meta_vultr_instance_hostname": model.LabelValue("np-2-d04e7829fa43"),
|
||||
"__meta_vultr_instance_server_status": model.LabelValue("ok"),
|
||||
"__meta_vultr_instance_vcpu_count": model.LabelValue("2"),
|
||||
"__meta_vultr_instance_ram_bytes": model.LabelValue("4096"),
|
||||
"__meta_vultr_instance_disk_gb": model.LabelValue("128"),
|
||||
"__meta_vultr_instance_allowed_bandwidth_gb": model.LabelValue("3000"),
|
||||
},
|
||||
} {
|
||||
t.Run(fmt.Sprintf("item %d", i), func(t *testing.T) {
|
||||
require.Equal(t, k, tg.Targets[i])
|
||||
})
|
||||
}
|
||||
}
|
|
@ -2538,6 +2538,83 @@ tls_config:
|
|||
See [the Prometheus uyuni-sd configuration file](/documentation/examples/prometheus-uyuni.yml)
|
||||
for a practical example on how to set up Uyuni Prometheus configuration.
|
||||
|
||||
### `<vultr_sd_config>`
|
||||
|
||||
Vultr SD configurations allow retrieving scrape targets from [Vultr](https://www.vultr.com/).
|
||||
|
||||
This service discovery uses the main IPv4 address by default, which that be
|
||||
changed with relabelling, as demonstrated in [the Prometheus vultr-sd
|
||||
configuration file](/documentation/examples/prometheus-vultr.yml).
|
||||
|
||||
The following meta labels are available on targets during [relabeling](#relabel_config):
|
||||
|
||||
* `__meta_vultr_instance_id` : A unique ID for the vultr Instance.
|
||||
* `__meta_vultr_instance_label` : The user-supplied label for this instance.
|
||||
* `__meta_vultr_instance_os` : The Operating System name.
|
||||
* `__meta_vultr_instance_os_id` : The Operating System id used by this instance.
|
||||
* `__meta_vultr_instance_region` : The Region id where the Instance is located.
|
||||
* `__meta_vultr_instance_plan` : A unique ID for the Plan.
|
||||
* `__meta_vultr_instance_main_ip` : The main IPv4 address.
|
||||
* `__meta_vultr_instance_internal_ip` : The private IP address.
|
||||
* `__meta_vultr_instance_main_ipv6` : The main IPv6 address.
|
||||
* `__meta_vultr_instance_features` : List of features that are available to the instance.
|
||||
* `__meta_vultr_instance_tags` : List of tags associated with the instance.
|
||||
* `__meta_vultr_instance_hostname` : The hostname for this instance.
|
||||
* `__meta_vultr_instance_server_status` : The server health status.
|
||||
* `__meta_vultr_instance_vcpu_count` : Number of vCPUs.
|
||||
* `__meta_vultr_instance_ram_bytes` : The amount of RAM in MB.
|
||||
* `__meta_vultr_instance_disk_gb` : The size of the disk in GB.
|
||||
* `__meta_vultr_instance_allowed_bandwidth_gb` : Monthly bandwidth quota in GB.
|
||||
|
||||
```yaml
|
||||
# Authentication information used to authenticate to the API server.
|
||||
# Note that `basic_auth` and `authorization` options are
|
||||
# mutually exclusive.
|
||||
# password and password_file are mutually exclusive.
|
||||
|
||||
# Optional HTTP basic authentication information, not currently supported by Vultr.
|
||||
basic_auth:
|
||||
[ username: <string> ]
|
||||
[ password: <secret> ]
|
||||
[ password_file: <string> ]
|
||||
|
||||
# Optional `Authorization` header configuration.
|
||||
authorization:
|
||||
# Sets the authentication type.
|
||||
[ type: <string> | default: Bearer ]
|
||||
# Sets the credentials. It is mutually exclusive with
|
||||
# `credentials_file`.
|
||||
[ credentials: <secret> ]
|
||||
# Sets the credentials to the credentials read from the configured file.
|
||||
# It is mutually exclusive with `credentials`.
|
||||
[ credentials_file: <filename> ]
|
||||
|
||||
# Optional OAuth 2.0 configuration.
|
||||
# Cannot be used at the same time as basic_auth or authorization.
|
||||
oauth2:
|
||||
[ <oauth2> ]
|
||||
|
||||
# Optional proxy URL.
|
||||
[ proxy_url: <string> ]
|
||||
|
||||
# Configure whether HTTP requests follow HTTP 3xx redirects.
|
||||
[ follow_redirects: <boolean> | default = true ]
|
||||
|
||||
# Whether to enable HTTP2.
|
||||
[ enable_http2: <bool> | default: true ]
|
||||
|
||||
# TLS configuration.
|
||||
tls_config:
|
||||
[ <tls_config> ]
|
||||
|
||||
# The port to scrape metrics from.
|
||||
[ port: <int> | default = 80 ]
|
||||
|
||||
# The time after which the instances are refreshed.
|
||||
[ refresh_interval: <duration> | default = 60s ]
|
||||
```
|
||||
|
||||
|
||||
### `<static_config>`
|
||||
|
||||
A `static_config` allows specifying a list of targets and a common label set
|
||||
|
@ -2813,6 +2890,10 @@ triton_sd_configs:
|
|||
uyuni_sd_configs:
|
||||
[ - <uyuni_sd_config> ... ]
|
||||
|
||||
# List of Vultr service discovery configurations.
|
||||
vultr_sd_configs:
|
||||
[ - <vultr_sd_config> ... ]
|
||||
|
||||
# List of labeled statically configured Alertmanagers.
|
||||
static_configs:
|
||||
[ - <static_config> ... ]
|
||||
|
|
24
documentation/examples/prometheus-vultr.yml
Normal file
24
documentation/examples/prometheus-vultr.yml
Normal file
|
@ -0,0 +1,24 @@
|
|||
# An example scrape configuration for running Prometheus with
|
||||
# Vultr.
|
||||
|
||||
scrape_configs:
|
||||
# Make Prometheus scrape itself for metrics.
|
||||
- job_name: "prometheus"
|
||||
static_configs:
|
||||
- targets: ["localhost:9090"]
|
||||
|
||||
# Discover Node Exporter instances to scrape.
|
||||
- job_name: "node"
|
||||
vultr_sd_configs:
|
||||
- authorization:
|
||||
credentials: "<replace with a Personal Access Token>"
|
||||
relabel_configs:
|
||||
# Only scrape targets that have a tag 'monitoring'.
|
||||
- source_labels: [__meta_vultr_instance_tags]
|
||||
regex: ".*,monitoring,.*"
|
||||
action: keep
|
||||
|
||||
# Use the public IPv6 address and port 9100 to scrape the target.
|
||||
- source_labels: [__meta_vultr_instance_main_ipv6]
|
||||
target_label: __address__
|
||||
replacement: "[$1]:9100"
|
4
go.mod
4
go.mod
|
@ -48,6 +48,7 @@ require (
|
|||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/vultr/govultr/v2 v2.17.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0
|
||||
go.opentelemetry.io/otel v1.7.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0
|
||||
|
@ -128,10 +129,11 @@ require (
|
|||
github.com/google/uuid v1.2.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.3.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.2 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-hclog v0.12.2 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.2.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/serf v0.9.6 // indirect
|
||||
|
|
8
go.sum
8
go.sum
|
@ -464,8 +464,10 @@ github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOj
|
|||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-hclog v0.12.2 h1:F1fdYblUEsxKiailtkhCCG2g4bipEgaHiDc8vffNpD4=
|
||||
github.com/hashicorp/go-hclog v0.12.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
|
@ -479,6 +481,8 @@ github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+
|
|||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
|
@ -820,6 +824,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1
|
|||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/vultr/govultr/v2 v2.17.0 h1:BHa6MQvQn4YNOw+ecfrbISOf4+3cvgofEQHKBSXt6t0=
|
||||
github.com/vultr/govultr/v2 v2.17.0/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
|
||||
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
|
||||
|
|
|
@ -70,6 +70,9 @@ import (
|
|||
// Register uyuni plugin.
|
||||
_ "github.com/prometheus/prometheus/discovery/uyuni"
|
||||
|
||||
// Register vultr plugin.
|
||||
_ "github.com/prometheus/prometheus/discovery/vultr"
|
||||
|
||||
// Register xds plugin.
|
||||
_ "github.com/prometheus/prometheus/discovery/xds"
|
||||
|
||||
|
|
Loading…
Reference in a new issue