mirror of
https://github.com/prometheus/prometheus.git
synced 2026-04-03 12:51:54 +02:00
Merge pull request #18287 from Skesov/feat/digitalocean-db-sd
discovery: add DigitalOcean Managed Databases service discovery
This commit is contained in:
commit
ced39f8a74
@ -1151,6 +1151,7 @@ var expectedConf = &Config{
|
||||
},
|
||||
Port: 80,
|
||||
RefreshInterval: model.Duration(60 * time.Second),
|
||||
Role: "droplets",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -34,29 +34,58 @@ import (
|
||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
)
|
||||
|
||||
// metaLabelPrefix is the meta prefix used for all meta labels.
|
||||
const (
|
||||
doLabel = model.MetaLabelPrefix + "digitalocean_"
|
||||
doLabelID = doLabel + "droplet_id"
|
||||
doLabelName = doLabel + "droplet_name"
|
||||
doLabelImage = doLabel + "image"
|
||||
doLabelImageName = doLabel + "image_name"
|
||||
doLabelPrivateIPv4 = doLabel + "private_ipv4"
|
||||
doLabelPublicIPv4 = doLabel + "public_ipv4"
|
||||
doLabelPublicIPv6 = doLabel + "public_ipv6"
|
||||
doLabelRegion = doLabel + "region"
|
||||
doLabelSize = doLabel + "size"
|
||||
doLabelStatus = doLabel + "status"
|
||||
doLabelFeatures = doLabel + "features"
|
||||
doLabelTags = doLabel + "tags"
|
||||
doLabelVPC = doLabel + "vpc"
|
||||
separator = ","
|
||||
metaLabelPrefix = model.MetaLabelPrefix + "digitalocean_"
|
||||
separator = ","
|
||||
)
|
||||
|
||||
const (
|
||||
doLabelID = metaLabelPrefix + "droplet_id"
|
||||
doLabelName = metaLabelPrefix + "droplet_name"
|
||||
doLabelImage = metaLabelPrefix + "image"
|
||||
doLabelImageName = metaLabelPrefix + "image_name"
|
||||
doLabelPrivateIPv4 = metaLabelPrefix + "private_ipv4"
|
||||
doLabelPublicIPv4 = metaLabelPrefix + "public_ipv4"
|
||||
doLabelPublicIPv6 = metaLabelPrefix + "public_ipv6"
|
||||
doLabelRegion = metaLabelPrefix + "region"
|
||||
doLabelSize = metaLabelPrefix + "size"
|
||||
doLabelStatus = metaLabelPrefix + "status"
|
||||
doLabelFeatures = metaLabelPrefix + "features"
|
||||
doLabelTags = metaLabelPrefix + "tags"
|
||||
doLabelVPC = metaLabelPrefix + "vpc"
|
||||
)
|
||||
|
||||
// Role is the role of the target within the DigitalOcean ecosystem.
|
||||
type Role string
|
||||
|
||||
const (
|
||||
// DropletsRole discovers targets from DigitalOcean Droplets.
|
||||
DropletsRole Role = "droplets"
|
||||
|
||||
// DatabasesRole discovers targets from DigitalOcean Managed Databases.
|
||||
DatabasesRole Role = "databases"
|
||||
)
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *Role) UnmarshalYAML(unmarshal func(any) error) error {
|
||||
if err := unmarshal((*string)(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
switch *c {
|
||||
case DropletsRole, DatabasesRole:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unknown DigitalOcean SD role %q", *c)
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultSDConfig is the default DigitalOcean SD configuration.
|
||||
var DefaultSDConfig = SDConfig{
|
||||
Port: 80,
|
||||
RefreshInterval: model.Duration(60 * time.Second),
|
||||
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
||||
Role: DropletsRole,
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -76,6 +105,10 @@ type SDConfig struct {
|
||||
|
||||
RefreshInterval model.Duration `yaml:"refresh_interval"`
|
||||
Port int `yaml:"port"`
|
||||
Role Role `yaml:"role"`
|
||||
|
||||
// Internal field for testing.
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// Name returns the name of the Config.
|
||||
@ -99,58 +132,78 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(any) error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Role == "" {
|
||||
return errors.New("role missing (one of: droplets, databases)")
|
||||
}
|
||||
|
||||
return c.HTTPClientConfig.Validate()
|
||||
}
|
||||
|
||||
// Discovery periodically performs DigitalOcean requests. It implements
|
||||
// the Discoverer interface.
|
||||
type Discovery struct {
|
||||
*refresh.Discovery
|
||||
client *godo.Client
|
||||
port int
|
||||
}
|
||||
|
||||
// NewDiscovery returns a new Discovery which periodically refreshes its targets.
|
||||
func NewDiscovery(conf *SDConfig, opts discovery.DiscovererOptions) (*Discovery, error) {
|
||||
func NewDiscovery(conf *SDConfig, opts discovery.DiscovererOptions) (discovery.Discoverer, error) {
|
||||
m, ok := opts.Metrics.(*digitaloceanMetrics)
|
||||
if !ok {
|
||||
return nil, errors.New("invalid discovery metrics type")
|
||||
}
|
||||
|
||||
d := &Discovery{
|
||||
port: conf.Port,
|
||||
}
|
||||
|
||||
rt, err := config.NewRoundTripperFromConfig(conf.HTTPClientConfig, "digitalocean_sd")
|
||||
r, err := newRefresher(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.client, err = godo.New(
|
||||
&http.Client{
|
||||
return refresh.NewDiscovery(
|
||||
refresh.Options{
|
||||
Logger: opts.Logger,
|
||||
Mech: "digitalocean",
|
||||
SetName: opts.SetName,
|
||||
Interval: time.Duration(conf.RefreshInterval),
|
||||
RefreshF: r.refresh,
|
||||
MetricsInstantiator: m.refreshMetrics,
|
||||
},
|
||||
), nil
|
||||
}
|
||||
|
||||
type refresher interface {
|
||||
refresh(context.Context) ([]*targetgroup.Group, error)
|
||||
}
|
||||
|
||||
func newRefresher(conf *SDConfig) (refresher, error) {
|
||||
httpClient := conf.HTTPClient
|
||||
if httpClient == nil {
|
||||
rt, err := config.NewRoundTripperFromConfig(conf.HTTPClientConfig, "digitalocean_sd")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
httpClient = &http.Client{
|
||||
Transport: rt,
|
||||
Timeout: time.Duration(conf.RefreshInterval),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
client, err := godo.New(
|
||||
httpClient,
|
||||
godo.SetUserAgent(version.PrometheusUserAgent()),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error setting up digital ocean agent: %w", err)
|
||||
}
|
||||
|
||||
d.Discovery = refresh.NewDiscovery(
|
||||
refresh.Options{
|
||||
Logger: opts.Logger,
|
||||
Mech: "digitalocean",
|
||||
SetName: opts.SetName,
|
||||
Interval: time.Duration(conf.RefreshInterval),
|
||||
RefreshF: d.refresh,
|
||||
MetricsInstantiator: m.refreshMetrics,
|
||||
},
|
||||
)
|
||||
return d, nil
|
||||
switch conf.Role {
|
||||
case DropletsRole:
|
||||
return &dropletsDiscovery{client: client, port: conf.Port}, nil
|
||||
case DatabasesRole:
|
||||
return &databasesDiscovery{client: client, port: conf.Port}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown DigitalOcean SD role %q", conf.Role)
|
||||
}
|
||||
|
||||
func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
||||
type dropletsDiscovery struct {
|
||||
client *godo.Client
|
||||
port int
|
||||
}
|
||||
|
||||
func (d *dropletsDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
||||
tg := &targetgroup.Group{
|
||||
Source: "DigitalOcean",
|
||||
}
|
||||
@ -213,7 +266,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
||||
return []*targetgroup.Group{tg}, nil
|
||||
}
|
||||
|
||||
func (d *Discovery) listDroplets(ctx context.Context) ([]godo.Droplet, error) {
|
||||
func (d *dropletsDiscovery) listDroplets(ctx context.Context) ([]godo.Droplet, error) {
|
||||
var (
|
||||
droplets []godo.Droplet
|
||||
opts = &godo.ListOptions{}
|
||||
|
||||
124
discovery/digitalocean/digitalocean_db.go
Normal file
124
discovery/digitalocean/digitalocean_db.go
Normal file
@ -0,0 +1,124 @@
|
||||
// Copyright 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 digitalocean
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/digitalocean/godo"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
)
|
||||
|
||||
const (
|
||||
dbLabelID = metaLabelPrefix + "db_id"
|
||||
dbLabelName = metaLabelPrefix + "db_name"
|
||||
dbLabelEngine = metaLabelPrefix + "db_engine"
|
||||
dbLabelVersion = metaLabelPrefix + "db_version"
|
||||
dbLabelStatus = metaLabelPrefix + "db_status"
|
||||
dbLabelRegion = metaLabelPrefix + "db_region"
|
||||
dbLabelSize = metaLabelPrefix + "db_size"
|
||||
dbLabelNumNodes = metaLabelPrefix + "db_num_nodes"
|
||||
dbLabelHost = metaLabelPrefix + "db_host"
|
||||
dbLabelPrivateHost = metaLabelPrefix + "db_private_host"
|
||||
dbLabelTagPrefix = metaLabelPrefix + "db_tag_"
|
||||
)
|
||||
|
||||
type databasesDiscovery struct {
|
||||
client *godo.Client
|
||||
port int
|
||||
}
|
||||
|
||||
func (d *databasesDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
||||
tg := &targetgroup.Group{
|
||||
Source: "DigitalOcean Databases",
|
||||
}
|
||||
|
||||
clusters, err := d.listClusters(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cluster := range clusters {
|
||||
labels := model.LabelSet{
|
||||
dbLabelID: model.LabelValue(cluster.ID),
|
||||
dbLabelName: model.LabelValue(cluster.Name),
|
||||
dbLabelEngine: model.LabelValue(cluster.EngineSlug),
|
||||
dbLabelVersion: model.LabelValue(cluster.VersionSlug),
|
||||
dbLabelStatus: model.LabelValue(cluster.Status),
|
||||
dbLabelRegion: model.LabelValue(cluster.RegionSlug),
|
||||
dbLabelSize: model.LabelValue(cluster.SizeSlug),
|
||||
dbLabelNumNodes: model.LabelValue(strconv.Itoa(cluster.NumNodes)),
|
||||
}
|
||||
|
||||
host := ""
|
||||
if cluster.PrivateConnection != nil {
|
||||
host = cluster.PrivateConnection.Host
|
||||
labels[dbLabelPrivateHost] = model.LabelValue(host)
|
||||
}
|
||||
|
||||
if cluster.Connection != nil {
|
||||
labels[dbLabelHost] = model.LabelValue(cluster.Connection.Host)
|
||||
if host == "" {
|
||||
host = cluster.Connection.Host
|
||||
}
|
||||
}
|
||||
|
||||
if host != "" {
|
||||
addr := net.JoinHostPort(host, strconv.FormatUint(uint64(d.port), 10))
|
||||
labels[model.AddressLabel] = model.LabelValue(addr)
|
||||
}
|
||||
|
||||
for _, tag := range cluster.Tags {
|
||||
labels[dbLabelTagPrefix+model.LabelName(tag)] = "true"
|
||||
}
|
||||
|
||||
tg.Targets = append(tg.Targets, labels)
|
||||
}
|
||||
return []*targetgroup.Group{tg}, nil
|
||||
}
|
||||
|
||||
func (d *databasesDiscovery) listClusters(ctx context.Context) ([]godo.Database, error) {
|
||||
var (
|
||||
clusters []godo.Database
|
||||
opts = &godo.ListOptions{
|
||||
Page: 1,
|
||||
PerPage: 100,
|
||||
}
|
||||
)
|
||||
for {
|
||||
paginatedClusters, resp, err := d.client.Databases.List(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while listing database clusters page %d: %w", opts.Page, err)
|
||||
}
|
||||
if len(paginatedClusters) == 0 {
|
||||
break
|
||||
}
|
||||
clusters = append(clusters, paginatedClusters...)
|
||||
|
||||
if resp.Links != nil && !resp.Links.IsLastPage() {
|
||||
page, err := resp.Links.CurrentPage()
|
||||
if err == nil {
|
||||
opts.Page = page + 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
opts.Page++
|
||||
}
|
||||
return clusters, nil
|
||||
}
|
||||
141
discovery/digitalocean/digitalocean_db_test.go
Normal file
141
discovery/digitalocean/digitalocean_db_test.go
Normal file
@ -0,0 +1,141 @@
|
||||
// Copyright 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 digitalocean
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDigitalOceanDBRefresh(t *testing.T) {
|
||||
mock := NewSDMock(t)
|
||||
mock.Setup()
|
||||
defer mock.ShutdownServer()
|
||||
|
||||
mock.HandleDatabasesList()
|
||||
|
||||
cfg := DefaultSDConfig
|
||||
cfg.Role = DatabasesRole
|
||||
cfg.Port = 9273
|
||||
cfg.HTTPClient = mock.Server.Client()
|
||||
|
||||
d, err := newRefresher(&cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Inject the mock URL into the godo client since we can't easily change it via HTTPClient.
|
||||
endpoint, _ := url.Parse(mock.Endpoint())
|
||||
d.(*databasesDiscovery).client.BaseURL = endpoint
|
||||
|
||||
tgs, err := d.refresh(context.Background())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, tgs, 1)
|
||||
|
||||
tg := tgs[0]
|
||||
require.NotNil(t, tg)
|
||||
require.Len(t, tg.Targets, 2)
|
||||
|
||||
expectedTargets := []struct {
|
||||
labels model.LabelSet
|
||||
}{
|
||||
{
|
||||
labels: model.LabelSet{
|
||||
"__address__": "do-fra1-pg-trading-001-do-user-XXXXX-0.f.db.ondigitalocean.com:9273",
|
||||
"__meta_digitalocean_db_id": "9cc10173-e9ea-4176-9dbc-a4cee4c4ff30",
|
||||
"__meta_digitalocean_db_name": "do-fra1-pg-trading-001",
|
||||
"__meta_digitalocean_db_engine": "pg",
|
||||
"__meta_digitalocean_db_version": "16",
|
||||
"__meta_digitalocean_db_status": "online",
|
||||
"__meta_digitalocean_db_region": "fra1",
|
||||
"__meta_digitalocean_db_size": "db-s-1vcpu-2gb",
|
||||
"__meta_digitalocean_db_num_nodes": "1",
|
||||
"__meta_digitalocean_db_host": "do-fra1-pg-trading-001-do-user-XXXXX-0.f.db.ondigitalocean.com",
|
||||
"__meta_digitalocean_db_tag_prod": "true",
|
||||
"__meta_digitalocean_db_tag_market": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
labels: model.LabelSet{
|
||||
"__address__": "private-db-host:9273",
|
||||
"__meta_digitalocean_db_id": "a0b1c2d3-e4f5-4677-8899-001122334455",
|
||||
"__meta_digitalocean_db_name": "private-db",
|
||||
"__meta_digitalocean_db_engine": "mysql",
|
||||
"__meta_digitalocean_db_version": "8",
|
||||
"__meta_digitalocean_db_status": "online",
|
||||
"__meta_digitalocean_db_region": "nyc1",
|
||||
"__meta_digitalocean_db_size": "db-s-2vcpu-4gb",
|
||||
"__meta_digitalocean_db_num_nodes": "2",
|
||||
"__meta_digitalocean_db_host": "public-db-host",
|
||||
"__meta_digitalocean_db_private_host": "private-db-host",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, expected := range expectedTargets {
|
||||
require.Equal(t, expected.labels, tg.Targets[i])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDigitalOceanDBRefreshPagination(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
page := r.URL.Query().Get("page")
|
||||
switch page {
|
||||
case "1", "":
|
||||
fmt.Fprint(w, `
|
||||
{
|
||||
"databases": [
|
||||
{"id": "db-1", "name": "db-1", "engine": "pg", "version": "16", "status": "online", "region": "fra1", "size": "db-s-1vcpu-2gb", "num_nodes": 1}
|
||||
],
|
||||
"links": {
|
||||
"pages": {
|
||||
"next": "http://example.com/v2/databases?page=2"
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
case "2":
|
||||
fmt.Fprint(w, `
|
||||
{
|
||||
"databases": [
|
||||
{"id": "db-2", "name": "db-2", "engine": "pg", "version": "16", "status": "online", "region": "fra1", "size": "db-s-1vcpu-2gb", "num_nodes": 1}
|
||||
]
|
||||
}
|
||||
`)
|
||||
default:
|
||||
fmt.Fprint(w, `{"databases": []}`)
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
cfg := DefaultSDConfig
|
||||
cfg.Role = DatabasesRole
|
||||
cfg.HTTPClient = ts.Client()
|
||||
|
||||
d, err := newRefresher(&cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
endpoint, _ := url.Parse(ts.URL)
|
||||
d.(*databasesDiscovery).client.BaseURL = endpoint
|
||||
|
||||
tgs, err := d.refresh(context.Background())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, tgs, 1)
|
||||
require.Len(t, tgs[0].Targets, 2)
|
||||
}
|
||||
@ -21,7 +21,6 @@ import (
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/promslog"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery"
|
||||
@ -57,15 +56,11 @@ func TestDigitalOceanSDRefresh(t *testing.T) {
|
||||
defer metrics.Unregister()
|
||||
defer refreshMetrics.Unregister()
|
||||
|
||||
d, err := NewDiscovery(&cfg, discovery.DiscovererOptions{
|
||||
Logger: promslog.NewNopLogger(),
|
||||
Metrics: metrics,
|
||||
SetName: "digitalocean",
|
||||
})
|
||||
d, err := newRefresher(&cfg)
|
||||
require.NoError(t, err)
|
||||
endpoint, err := url.Parse(sdmock.Mock.Endpoint())
|
||||
require.NoError(t, err)
|
||||
d.client.BaseURL = endpoint
|
||||
d.(*dropletsDiscovery).client.BaseURL = endpoint
|
||||
|
||||
ctx := context.Background()
|
||||
tgs, err := d.refresh(ctx)
|
||||
|
||||
@ -645,3 +645,68 @@ func (m *SDMock) HandleDropletsList() {
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// HandleDatabasesList mocks database clusters list.
|
||||
func (m *SDMock) HandleDatabasesList() {
|
||||
m.Mux.HandleFunc("/v2/databases", func(w http.ResponseWriter, r *http.Request) {
|
||||
page := r.URL.Query().Get("page")
|
||||
switch page {
|
||||
case "1", "":
|
||||
fmt.Fprint(w, `
|
||||
{
|
||||
"databases": [
|
||||
{
|
||||
"id": "9cc10173-e9ea-4176-9dbc-a4cee4c4ff30",
|
||||
"name": "do-fra1-pg-trading-001",
|
||||
"engine": "pg",
|
||||
"version": "16",
|
||||
"status": "online",
|
||||
"region": "fra1",
|
||||
"size": "db-s-1vcpu-2gb",
|
||||
"num_nodes": 1,
|
||||
"connection": {
|
||||
"host": "do-fra1-pg-trading-001-do-user-XXXXX-0.f.db.ondigitalocean.com",
|
||||
"port": 25060,
|
||||
"user": "doadmin",
|
||||
"password": "XXX",
|
||||
"database": "defaultdb",
|
||||
"ssl": true
|
||||
},
|
||||
"tags": ["prod", "market"]
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"pages": {
|
||||
"next": "http://example.com/v2/databases?page=2"
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
case "2":
|
||||
fmt.Fprint(w, `
|
||||
{
|
||||
"databases": [
|
||||
{
|
||||
"id": "a0b1c2d3-e4f5-4677-8899-001122334455",
|
||||
"name": "private-db",
|
||||
"engine": "mysql",
|
||||
"version": "8",
|
||||
"status": "online",
|
||||
"region": "nyc1",
|
||||
"size": "db-s-2vcpu-4gb",
|
||||
"num_nodes": 2,
|
||||
"connection": {
|
||||
"host": "public-db-host"
|
||||
},
|
||||
"private_connection": {
|
||||
"host": "private-db-host"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
`)
|
||||
default:
|
||||
fmt.Fprint(w, `{"databases": []}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -1501,10 +1501,15 @@ metadata and a single tag).
|
||||
### `<digitalocean_sd_config>`
|
||||
|
||||
DigitalOcean SD configurations allow retrieving scrape targets from [DigitalOcean's](https://www.digitalocean.com/)
|
||||
Droplets API.
|
||||
This service discovery uses the public IPv4 address by default, by that can be
|
||||
changed with relabeling, as demonstrated in [the Prometheus digitalocean-sd
|
||||
configuration file](/documentation/examples/prometheus-digitalocean.yml).
|
||||
API.
|
||||
This service discovery supports multiple roles through the `role` parameter.
|
||||
|
||||
One of the following `role` types can be configured to discover targets:
|
||||
|
||||
#### `droplets`
|
||||
|
||||
The `droplets` role discovers targets from DigitalOcean Droplets. The public IPv4 address is used by default,
|
||||
but may be changed with relabeling.
|
||||
|
||||
The following meta labels are available on targets during [relabeling](#relabel_config):
|
||||
|
||||
@ -1522,11 +1527,33 @@ The following meta labels are available on targets during [relabeling](#relabel_
|
||||
* `__meta_digitalocean_tags`: the comma-separated list of tags of the droplet
|
||||
* `__meta_digitalocean_vpc`: the id of the droplet's VPC
|
||||
|
||||
#### `databases`
|
||||
|
||||
The `databases` role discovers targets from DigitalOcean Managed Databases.
|
||||
|
||||
The following meta labels are available on targets during [relabeling](#relabel_config):
|
||||
|
||||
* `__meta_digitalocean_db_id`: the id of the database cluster
|
||||
* `__meta_digitalocean_db_name`: the name of the database cluster
|
||||
* `__meta_digitalocean_db_engine`: the engine of the database cluster (e.g., `pg`, `mysql`, `redis`, `mongodb`)
|
||||
* `__meta_digitalocean_db_version`: the version of the engine
|
||||
* `__meta_digitalocean_db_status`: the status of the database cluster
|
||||
* `__meta_digitalocean_db_region`: the region of the database cluster
|
||||
* `__meta_digitalocean_db_size`: the size of the database cluster
|
||||
* `__meta_digitalocean_db_num_nodes`: the number of nodes in the database cluster
|
||||
* `__meta_digitalocean_db_host`: the public host of the database cluster
|
||||
* `__meta_digitalocean_db_private_host`: the private host of the database cluster
|
||||
* `__meta_digitalocean_db_tag_<tagname>`: each tag of the database cluster, with its value set to `true`
|
||||
|
||||
```yaml
|
||||
# The DigitalOcean role to use for service discovery.
|
||||
# Must be one of: droplets or databases.
|
||||
[ role: <string> | default = droplets ]
|
||||
|
||||
# The port to scrape metrics from.
|
||||
[ port: <int> | default = 80 ]
|
||||
|
||||
# The time after which the droplets are refreshed.
|
||||
# The time after which the targets are refreshed.
|
||||
[ refresh_interval: <duration> | default = 60s ]
|
||||
|
||||
# HTTP client settings, including authentication methods (such as basic auth and
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user