add support for scaleway service discovery (#8555)

Co-authored-by: Patrik <patrik@ptrk.io>
Co-authored-by: Julien Pivotto <roidelapluie@inuits.eu>

Signed-off-by: Rémy Léone <rleone@scaleway.com>
This commit is contained in:
Rémy Léone 2021-03-10 15:10:17 +01:00 committed by GitHub
parent ad5ed416ba
commit f690b811c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 742 additions and 1 deletions

View file

@ -40,6 +40,7 @@ import (
"github.com/prometheus/prometheus/discovery/kubernetes" "github.com/prometheus/prometheus/discovery/kubernetes"
"github.com/prometheus/prometheus/discovery/marathon" "github.com/prometheus/prometheus/discovery/marathon"
"github.com/prometheus/prometheus/discovery/openstack" "github.com/prometheus/prometheus/discovery/openstack"
"github.com/prometheus/prometheus/discovery/scaleway"
"github.com/prometheus/prometheus/discovery/targetgroup" "github.com/prometheus/prometheus/discovery/targetgroup"
"github.com/prometheus/prometheus/discovery/triton" "github.com/prometheus/prometheus/discovery/triton"
"github.com/prometheus/prometheus/discovery/zookeeper" "github.com/prometheus/prometheus/discovery/zookeeper"
@ -742,6 +743,42 @@ var expectedConf = &Config{
}, },
}, },
}, },
{
JobName: "scaleway",
HonorTimestamps: true,
ScrapeInterval: model.Duration(15 * time.Second),
ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
HTTPClientConfig: config.HTTPClientConfig{FollowRedirects: true},
MetricsPath: DefaultScrapeConfig.MetricsPath,
Scheme: DefaultScrapeConfig.Scheme,
ServiceDiscoveryConfigs: discovery.Configs{
&scaleway.SDConfig{
APIURL: "https://api.scaleway.com",
AccessKey: "SCWXXXXXXXXXXXXXXXXX",
HTTPClientConfig: config.HTTPClientConfig{FollowRedirects: true},
Port: 80,
Project: "11111111-1111-1111-1111-111111111112",
RefreshInterval: model.Duration(60 * time.Second),
Role: "instance",
SecretKey: "11111111-1111-1111-1111-111111111111",
Zone: "fr-par-1",
},
&scaleway.SDConfig{
APIURL: "https://api.scaleway.com",
AccessKey: "SCWXXXXXXXXXXXXXXXXX",
HTTPClientConfig: config.HTTPClientConfig{FollowRedirects: true},
Port: 80,
Project: "11111111-1111-1111-1111-111111111112",
RefreshInterval: model.Duration(60 * time.Second),
Role: "baremetal",
SecretKey: "11111111-1111-1111-1111-111111111111",
Zone: "fr-par-1",
},
},
},
}, },
AlertingConfig: AlertingConfig{ AlertingConfig: AlertingConfig{
AlertmanagerConfigs: []*AlertmanagerConfig{ AlertmanagerConfigs: []*AlertmanagerConfig{
@ -826,7 +863,7 @@ func TestElideSecrets(t *testing.T) {
yamlConfig := string(config) yamlConfig := string(config)
matches := secretRe.FindAllStringIndex(yamlConfig, -1) matches := secretRe.FindAllStringIndex(yamlConfig, -1)
require.Equal(t, 10, len(matches), "wrong number of secret matches found") require.Equal(t, 12, len(matches), "wrong number of secret matches found")
require.NotContains(t, yamlConfig, "mysecret", require.NotContains(t, yamlConfig, "mysecret",
"yaml marshal reveals authentication credentials.") "yaml marshal reveals authentication credentials.")
} }

View file

@ -298,6 +298,17 @@ scrape_configs:
eureka_sd_configs: eureka_sd_configs:
- server: 'http://eureka.example.com:8761/eureka' - server: 'http://eureka.example.com:8761/eureka'
- job_name: scaleway
scaleway_sd_configs:
- role: instance
project_id: 11111111-1111-1111-1111-111111111112
access_key: SCWXXXXXXXXXXXXXXXXX
secret_key: 11111111-1111-1111-1111-111111111111
- role: baremetal
project_id: 11111111-1111-1111-1111-111111111112
access_key: SCWXXXXXXXXXXXXXXXXX
secret_key: 11111111-1111-1111-1111-111111111111
alerting: alerting:
alertmanagers: alertmanagers:
- scheme: https - scheme: https

4
config/testdata/scaleway_role.bad.yml vendored Normal file
View file

@ -0,0 +1,4 @@
scrape_configs:
- scaleway_sd_configs:
- role: invalid

View file

@ -29,6 +29,7 @@ import (
_ "github.com/prometheus/prometheus/discovery/kubernetes" // register kubernetes _ "github.com/prometheus/prometheus/discovery/kubernetes" // register kubernetes
_ "github.com/prometheus/prometheus/discovery/marathon" // register marathon _ "github.com/prometheus/prometheus/discovery/marathon" // register marathon
_ "github.com/prometheus/prometheus/discovery/openstack" // register openstack _ "github.com/prometheus/prometheus/discovery/openstack" // register openstack
_ "github.com/prometheus/prometheus/discovery/scaleway" // register scaleway
_ "github.com/prometheus/prometheus/discovery/triton" // register triton _ "github.com/prometheus/prometheus/discovery/triton" // register triton
_ "github.com/prometheus/prometheus/discovery/zookeeper" // register zookeeper _ "github.com/prometheus/prometheus/discovery/zookeeper" // register zookeeper
) )

View file

@ -0,0 +1,192 @@
// Copyright 2021 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 scaleway
import (
"context"
"fmt"
"net"
"net/http"
"strconv"
"strings"
"time"
"github.com/prometheus/common/config"
"github.com/prometheus/common/model"
"github.com/prometheus/common/version"
"github.com/prometheus/prometheus/discovery/refresh"
"github.com/prometheus/prometheus/discovery/targetgroup"
"github.com/scaleway/scaleway-sdk-go/api/baremetal/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
)
type baremetalDiscovery struct {
*refresh.Discovery
client *scw.Client
port int
zone string
project string
accessKey string
secretKey string
nameFilter string
tagsFilter []string
}
const (
baremetalLabelPrefix = metaLabelPrefix + "baremetal_"
baremetalIDLabel = baremetalLabelPrefix + "id"
baremetalPublicIPv4Label = baremetalLabelPrefix + "public_ipv4"
baremetalPublicIPv6Label = baremetalLabelPrefix + "public_ipv6"
baremetalNameLabel = baremetalLabelPrefix + "name"
baremetalOSNameLabel = baremetalLabelPrefix + "os_name"
baremetalOSVersionLabel = baremetalLabelPrefix + "os_version"
baremetalProjectLabel = baremetalLabelPrefix + "project_id"
baremetalStatusLabel = baremetalLabelPrefix + "status"
baremetalTagsLabel = baremetalLabelPrefix + "tags"
baremetalTypeLabel = baremetalLabelPrefix + "type"
baremetalZoneLabel = baremetalLabelPrefix + "zone"
)
func newBaremetalDiscovery(conf *SDConfig) (*baremetalDiscovery, error) {
d := &baremetalDiscovery{
port: conf.Port,
zone: conf.Zone,
project: conf.Project,
accessKey: conf.AccessKey,
secretKey: string(conf.SecretKey),
nameFilter: conf.NameFilter,
tagsFilter: conf.TagsFilter,
}
rt, err := config.NewRoundTripperFromConfig(conf.HTTPClientConfig, "scaleway_sd", false, false)
if err != nil {
return nil, err
}
profile, err := loadProfile(conf)
if err != nil {
return nil, err
}
d.client, err = scw.NewClient(
scw.WithHTTPClient(&http.Client{
Transport: rt,
Timeout: time.Duration(conf.RefreshInterval),
}),
scw.WithUserAgent(fmt.Sprintf("Prometheus/%s", version.Version)),
scw.WithProfile(profile),
)
if err != nil {
return nil, fmt.Errorf("error setting up scaleway client: %w", err)
}
return d, nil
}
func (d *baremetalDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
api := baremetal.NewAPI(d.client)
req := &baremetal.ListServersRequest{}
if d.nameFilter != "" {
req.Name = scw.StringPtr(d.nameFilter)
}
if d.tagsFilter != nil {
req.Tags = d.tagsFilter
}
servers, err := api.ListServers(req, scw.WithAllPages(), scw.WithContext(ctx))
if err != nil {
return nil, err
}
offers, err := api.ListOffers(&baremetal.ListOffersRequest{}, scw.WithAllPages())
if err != nil {
return nil, err
}
osFullList, err := api.ListOS(&baremetal.ListOSRequest{}, scw.WithAllPages())
if err != nil {
return nil, err
}
var targets []model.LabelSet
for _, server := range servers.Servers {
labels := model.LabelSet{
baremetalIDLabel: model.LabelValue(server.ID),
baremetalNameLabel: model.LabelValue(server.Name),
baremetalZoneLabel: model.LabelValue(server.Zone.String()),
baremetalStatusLabel: model.LabelValue(server.Status),
baremetalProjectLabel: model.LabelValue(server.ProjectID),
}
for _, offer := range offers.Offers {
if server.OfferID == offer.ID {
labels[baremetalTypeLabel] = model.LabelValue(offer.Name)
break
}
}
if server.Install != nil {
for _, os := range osFullList.Os {
if server.Install.OsID == os.ID {
labels[baremetalOSNameLabel] = model.LabelValue(os.Name)
labels[baremetalOSVersionLabel] = model.LabelValue(os.Version)
break
}
}
}
if len(server.Tags) > 0 {
// We surround the separated list with the separator as well. This way regular expressions
// in relabeling rules don't have to consider tag positions.
tags := separator + strings.Join(server.Tags, separator) + separator
labels[baremetalTagsLabel] = model.LabelValue(tags)
}
for _, ip := range server.IPs {
switch v := ip.Version.String(); v {
case "IPv4":
if _, ok := labels[baremetalPublicIPv4Label]; ok {
// If the server has multiple IPv4, we only take the first one.
// This should not happen.
continue
}
labels[baremetalPublicIPv4Label] = model.LabelValue(ip.Address.String())
// We always default the __address__ to IPv4.
addr := net.JoinHostPort(ip.Address.String(), strconv.FormatUint(uint64(d.port), 10))
labels[model.AddressLabel] = model.LabelValue(addr)
case "IPv6":
if _, ok := labels[baremetalPublicIPv6Label]; ok {
// If the server has multiple IPv6, we only take the first one.
// This should not happen.
continue
}
labels[baremetalPublicIPv6Label] = model.LabelValue(ip.Address.String())
if _, ok := labels[model.AddressLabel]; !ok {
// This server does not have an IPv4 or we have not parsed it
// yet.
addr := net.JoinHostPort(ip.Address.String(), strconv.FormatUint(uint64(d.port), 10))
labels[model.AddressLabel] = model.LabelValue(addr)
}
default:
return nil, fmt.Errorf("unknown IP version: %s", v)
}
}
targets = append(targets, labels)
}
return []*targetgroup.Group{{Source: "scaleway", Targets: targets}}, nil
}

View file

@ -0,0 +1,155 @@
// Copyright 2021 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 scaleway
import (
"context"
"fmt"
"net"
"net/http"
"strconv"
"strings"
"time"
"github.com/prometheus/common/config"
"github.com/prometheus/common/model"
"github.com/prometheus/common/version"
"github.com/prometheus/prometheus/discovery/refresh"
"github.com/prometheus/prometheus/discovery/targetgroup"
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
)
const (
instanceLabelPrefix = metaLabelPrefix + "instance_"
instanceIDLabel = instanceLabelPrefix + "id"
instancePrivateIPv4 = instanceLabelPrefix + "private_ipv4"
instancePublicIPv4 = instanceLabelPrefix + "public_ipv4"
instancePublicIPv6 = instanceLabelPrefix + "public_ipv6"
instanceImageNameLabel = instanceLabelPrefix + "image_name"
instanceNameLabel = instanceLabelPrefix + "name"
instanceProjectLabel = instanceLabelPrefix + "project_id"
instanceStateLabel = instanceLabelPrefix + "status"
instanceTagsLabel = instanceLabelPrefix + "tags"
instanceTypeLabel = instanceLabelPrefix + "type"
instanceZoneLabel = instanceLabelPrefix + "zone"
)
type instanceDiscovery struct {
*refresh.Discovery
client *scw.Client
port int
zone string
project string
accessKey string
secretKey string
nameFilter string
tagsFilter []string
}
func newInstanceDiscovery(conf *SDConfig) (*instanceDiscovery, error) {
d := &instanceDiscovery{
port: conf.Port,
zone: conf.Zone,
project: conf.Project,
accessKey: conf.AccessKey,
secretKey: string(conf.SecretKey),
nameFilter: conf.NameFilter,
tagsFilter: conf.TagsFilter,
}
rt, err := config.NewRoundTripperFromConfig(conf.HTTPClientConfig, "scaleway_sd", false, false)
if err != nil {
return nil, err
}
profile, err := loadProfile(conf)
if err != nil {
return nil, err
}
d.client, err = scw.NewClient(
scw.WithHTTPClient(&http.Client{
Transport: rt,
Timeout: time.Duration(conf.RefreshInterval),
}),
scw.WithUserAgent(fmt.Sprintf("Prometheus/%s", version.Version)),
scw.WithProfile(profile),
)
if err != nil {
return nil, fmt.Errorf("error setting up scaleway client: %w", err)
}
return d, nil
}
func (d *instanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
api := instance.NewAPI(d.client)
req := &instance.ListServersRequest{}
if d.nameFilter != "" {
req.Name = scw.StringPtr(d.nameFilter)
}
if d.tagsFilter != nil {
req.Tags = d.tagsFilter
}
servers, err := api.ListServers(req, scw.WithAllPages(), scw.WithContext(ctx))
if err != nil {
return nil, err
}
var targets []model.LabelSet
for _, server := range servers.Servers {
labels := model.LabelSet{
instanceIDLabel: model.LabelValue(server.ID),
instanceImageNameLabel: model.LabelValue(server.Image.Name),
instanceNameLabel: model.LabelValue(server.Name),
instanceProjectLabel: model.LabelValue(server.Project),
instanceStateLabel: model.LabelValue(server.State),
instanceTypeLabel: model.LabelValue(server.CommercialType),
instanceZoneLabel: model.LabelValue(server.Zone.String()),
}
if len(server.Tags) > 0 {
// We surround the separated list with the separator as well. This way regular expressions
// in relabeling rules don't have to consider tag positions.
tags := separator + strings.Join(server.Tags, separator) + separator
labels[instanceTagsLabel] = model.LabelValue(tags)
}
if server.IPv6 != nil {
labels[instancePublicIPv6] = model.LabelValue(server.IPv6.Address.String())
}
if server.PublicIP != nil {
labels[instancePublicIPv4] = model.LabelValue(server.PublicIP.Address.String())
}
if server.PrivateIP != nil {
labels[instancePrivateIPv4] = model.LabelValue(*server.PrivateIP)
addr := net.JoinHostPort(*server.PrivateIP, strconv.FormatUint(uint64(d.port), 10))
labels[model.AddressLabel] = model.LabelValue(addr)
targets = append(targets, labels)
}
}
return []*targetgroup.Group{{Source: "scaleway", Targets: targets}}, nil
}

View file

@ -0,0 +1,200 @@
// Copyright 2021 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 scaleway
import (
"context"
"time"
"github.com/go-kit/kit/log"
"github.com/pkg/errors"
"github.com/prometheus/common/config"
"github.com/prometheus/common/model"
"github.com/prometheus/prometheus/discovery"
"github.com/prometheus/prometheus/discovery/refresh"
"github.com/prometheus/prometheus/discovery/targetgroup"
"github.com/scaleway/scaleway-sdk-go/scw"
)
// metaLabelPrefix is the meta prefix used for all meta labels.
// in this discovery.
const (
metaLabelPrefix = model.MetaLabelPrefix + "scaleway_"
separator = ","
)
// role is the role of the target within the Scaleway Ecosystem.
type role string
// The valid options for role.
const (
// Scaleway Elements Baremetal
// https://www.scaleway.com/en/bare-metal-servers/
roleBaremetal role = "baremetal"
// Scaleway Elements Instance
// https://www.scaleway.com/en/virtual-instances/
roleInstance role = "instance"
)
// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (c *role) UnmarshalYAML(unmarshal func(interface{}) error) error {
if err := unmarshal((*string)(c)); err != nil {
return err
}
switch *c {
case roleInstance, roleBaremetal:
return nil
default:
return errors.Errorf("unknown role %q", *c)
}
}
// DefaultSDConfig is the default Scaleway Service Discovery configuration.
var DefaultSDConfig = SDConfig{
Port: 80,
RefreshInterval: model.Duration(60 * time.Second),
HTTPClientConfig: config.DefaultHTTPClientConfig,
Zone: scw.ZoneFrPar1.String(),
APIURL: "https://api.scaleway.com",
}
type SDConfig struct {
// Project: The Scaleway Project ID used to filter discovery on.
Project string `yaml:"project_id"`
// APIURL: URL of the Scaleway API to use.
APIURL string `yaml:"api_url,omitempty"`
// Zone: The zone of the scrape targets.
// If you need to configure multiple zones use multiple scaleway_sd_configs
Zone string `yaml:"zone"`
// AccessKey used to authenticate on Scaleway APIs.
AccessKey string `yaml:"access_key"`
// SecretKey used to authenticate on Scaleway APIs.
SecretKey config.Secret `yaml:"secret_key"`
// NameFilter to filter on during the ListServers.
NameFilter string `yaml:"name_filter,omitempty"`
// TagsFilter to filter on during the ListServers.
TagsFilter []string `yaml:"tags_filter,omitempty"`
HTTPClientConfig config.HTTPClientConfig `yaml:",inline"`
RefreshInterval model.Duration `yaml:"refresh_interval"`
Port int `yaml:"port"`
// Role can be either instance or baremetal
Role role `yaml:"role"`
}
func (c SDConfig) Name() string {
return "scaleway"
}
// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
*c = DefaultSDConfig
type plain SDConfig
err := unmarshal((*plain)(c))
if err != nil {
return err
}
if c.Role == "" {
return errors.New("role missing (one of: instance, baremetal)")
}
if c.Project == "" {
return errors.New("project_id is mandatory")
}
if c.SecretKey == "" {
return errors.New("secret_key is mandatory")
}
if c.AccessKey == "" {
return errors.New("access_key is mandatory")
}
profile, err := loadProfile(c)
if err != nil {
return err
}
_, err = scw.NewClient(
scw.WithProfile(profile),
)
if err != nil {
return err
}
return c.HTTPClientConfig.Validate()
}
func (c SDConfig) NewDiscoverer(options discovery.DiscovererOptions) (discovery.Discoverer, error) {
return NewDiscovery(&c, options.Logger)
}
// SetDirectory joins any relative file paths with dir.
func (c *SDConfig) SetDirectory(dir string) {
c.HTTPClientConfig.SetDirectory(dir)
}
func init() {
discovery.RegisterConfig(&SDConfig{})
}
// Discovery periodically performs Scaleway requests. It implements
// the Discoverer interface.
type Discovery struct {
}
func NewDiscovery(conf *SDConfig, logger log.Logger) (*refresh.Discovery, error) {
r, err := newRefresher(conf)
if err != nil {
return nil, err
}
return refresh.NewDiscovery(
logger,
"scaleway",
time.Duration(conf.RefreshInterval),
r.refresh,
), nil
}
type refresher interface {
refresh(context.Context) ([]*targetgroup.Group, error)
}
func newRefresher(conf *SDConfig) (refresher, error) {
switch conf.Role {
case roleBaremetal:
return newBaremetalDiscovery(conf)
case roleInstance:
return newInstanceDiscovery(conf)
}
return nil, errors.New("unknown Scaleway discovery role")
}
func loadProfile(sdConfig *SDConfig) (*scw.Profile, error) {
// Profile coming from Prometheus Configuration file
prometheusConfigProfile := &scw.Profile{
DefaultZone: scw.StringPtr(sdConfig.Zone),
APIURL: scw.StringPtr(sdConfig.APIURL),
SecretKey: scw.StringPtr(string(sdConfig.SecretKey)),
AccessKey: scw.StringPtr(sdConfig.AccessKey),
DefaultProjectID: scw.StringPtr(sdConfig.Project),
SendTelemetry: scw.BoolPtr(false),
}
return prometheusConfigProfile, nil
}

View file

@ -246,6 +246,10 @@ nerve_sd_configs:
openstack_sd_configs: openstack_sd_configs:
[ - <openstack_sd_config> ... ] [ - <openstack_sd_config> ... ]
# List of Scaleway service discovery configurations.
scaleway_sd_configs:
[ - <scaleway_sd_config> ... ]
# List of Zookeeper Serverset service discovery configurations. # List of Zookeeper Serverset service discovery configurations.
serverset_sd_configs: serverset_sd_configs:
[ - <serverset_sd_config> ... ] [ - <serverset_sd_config> ... ]
@ -1523,6 +1527,93 @@ See [the Prometheus eureka-sd configuration file](/documentation/examples/promet
for a practical example on how to set up your Eureka app and your Prometheus for a practical example on how to set up your Eureka app and your Prometheus
configuration. configuration.
### `<scaleway_sd_config>`
Scaleway SD configurations allow retrieving scrape targets from [Scaleway instances](https://www.scaleway.com/en/virtual-instances/) and [baremetal services](https://www.scaleway.com/en/bare-metal-servers/).
The following meta labels are available on targets during [relabeling](#relabel_config):
#### Instance role
* `__meta_scaleway_instance_id`: the id of the instance
* `__meta_scaleway_instance_private_ipv4`: the private ipv4 address of the instance
* `__meta_scaleway_instance_public_ipv4`: the public ipv4 address of the instance
* `__meta_scaleway_instance_public_ipv6`: the public ipv6 address of the instance
* `__meta_scaleway_instance_image_name`: name of the server image
* `__meta_scaleway_instance_name`: name of the server
* `__meta_scaleway_instance_project_id`: project id of the server
* `__meta_scaleway_instance_status`: status of the server
* `__meta_scaleway_instance_tags`: the list of tags of the target joined by the tag separator
* `__meta_scaleway_instance_type`: commercial type of the server
* `__meta_scaleway_instance_zone`: zone of the instance (ex: `fr-par-1`, complete list on <https://developers.scaleway.com/en/>)
This role uses the private IPv4 address by default. This can be
changed with relabelling, as demonstrated in [the Prometheus scaleway-sd
configuration file](/documentation/examples/prometheus-scaleway.yml).
#### Baremetal role
* `__meta_scaleway_baremetal_id`: the id of the server
* `__meta_scaleway_baremetal_public_ipv4`: the public ipv4 address of the server
* `__meta_scaleway_baremetal_public_ipv6`: the public ipv6 address of the server
* `__meta_scaleway_baremetal_ipaddress_order`: zero-based order of the address in the server
* `__meta_scaleway_baremetal_name`: name of the server
* `__meta_scaleway_baremetal_os_name`: name of the os used
* `__meta_scaleway_baremetal_os_version`: version of the os used
* `__meta_scaleway_baremetal_project_id`: project id of the server
* `__meta_scaleway_baremetal_status`: status of the server
* `__meta_scaleway_baremetal_tags`: tag list of the server
* `__meta_scaleway_baremetal_type`: commercial type of the server
* `__meta_scaleway_baremetal_zone`: zone of the server (ex: `fr-par-1`, complete list on <https://developers.scaleway.com/en/>)
This role uses the public IPv4 address by default. This can be
changed with relabelling, as demonstrated in [the Prometheus scaleway-sd
configuration file](/documentation/examples/prometheus-scaleway.yml).
See below for the configuration options for Scaleway discovery:
```yaml
# Access key to use. https://console.scaleway.com/project/credentials
access_key: <string>
# Secret key to use when listing targets. https://console.scaleway.com/project/credentials
secret_key: <secret>
# Project ID of the targets.
project_id: <string>
# Role of the targets to retrieve. Must be `instance` or `baremetal`.
role: <string>
# The port to scrape metrics from.
[ port: <int> | default = 80 ]
# API URL to use when doing the server listing requests.
[ api_url: <string> | default = "https://api.scaleway.com" ]
# Zone is the availability zone of your targets (e.g. fr-par-1).
[ zone: <string> | default = fr-par-1 ]
# NameFilter specify a name filter (works as a LIKE) to apply on the server listing request.
[ name_filter: <string> ]
# TagsFilter specify a tag filter (a server needs to have all defined tags to be listed) to apply on the server listing request.
tags_filter:
[ - <string> ]
# Refresh interval to re-read the targets list.
[ refresh_interval: <duration> | default = 60s ]
# Configure whether HTTP requests follow HTTP 3xx redirects.
[ follow_redirects: <bool> | default = true ]
# Optional proxy URL.
[ proxy_url: <string> ]
# TLS configuration.
tls_config:
[ <tls_config> ]
```
### `<static_config>` ### `<static_config>`
@ -1746,6 +1837,10 @@ nerve_sd_configs:
openstack_sd_configs: openstack_sd_configs:
[ - <openstack_sd_config> ... ] [ - <openstack_sd_config> ... ]
# List of Scaleway service discovery configurations.
scaleway_sd_configs:
[ - <scaleway_sd_config> ... ]
# List of Zookeeper Serverset service discovery configurations. # List of Zookeeper Serverset service discovery configurations.
serverset_sd_configs: serverset_sd_configs:
[ - <serverset_sd_config> ... ] [ - <serverset_sd_config> ... ]

View file

@ -0,0 +1,41 @@
# A example scrape configuration for running Prometheus with Scaleway.
scrape_configs:
- job_name: 'prometheus'
scaleway_sd_configs:
- role: instance
# You can find you project ID here: https://console.scaleway.com/project/settings
project_id: 11111111-1111-1111-1111-111111111111
# Replace with Scaleway Credentials: https://console.scaleway.com/project/credentials
access_key: SCWXXXXXXXXXXXXXXXXX
secret_key: 11111111-1111-1111-1111-111111111111
relabel_configs:
# Only scrape targets that have a tag 'prometheus'.
- source_labels: [__meta_scaleway_instance_tags]
regex: '.*,prometheus,.*'
action: keep
# Use the public IPv6 address and port 9100 to scrape the target.
- source_labels: [__meta_scaleway_instance_public_ipv6]
target_label: __address__
replacement: '[$1]:9090'
# Add the zone as label
- source_labels: [__meta_scaleway_instance_zone]
target_label: scw_zone
- job_name: 'node'
scaleway_sd_configs:
- role: baremetal
# You can find you project ID here: https://console.scaleway.com/project/settings
project_id: 11111111-1111-1111-1111-111111111111
zone: fr-par-2
# Replace with Scaleway Credentials: https://console.scaleway.com/project/credentials
access_key: SCWXXXXXXXXXXXXXXXXX
secret_key: 11111111-1111-1111-1111-111111111111
relabel_configs:
# Filter out servers that are not physically in the datacenter.
- source_labels: [__meta_scaleway_baremetal_status]
regex: '(delivering|out_of_stock)'
action: drop
# Use the public IPv6 address and port 9100 to scrape the target.
- source_labels: [__meta_scaleway_baremetal_public_ipv6]
target_label: __address__
replacement: '[$1]:9100'

1
go.mod
View file

@ -50,6 +50,7 @@ require (
github.com/prometheus/client_model v0.2.0 github.com/prometheus/client_model v0.2.0
github.com/prometheus/common v0.18.0 github.com/prometheus/common v0.18.0
github.com/prometheus/exporter-toolkit v0.5.1 github.com/prometheus/exporter-toolkit v0.5.1
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210223165440-c65ae3540d44
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0

4
go.sum
View file

@ -161,6 +161,8 @@ github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245 h1:9cOfvEwjQxdwKu
github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/digitalocean/godo v1.57.0 h1:uCpe0sRIZ/sJWxWDsJyBPBjUfSvxop+WHkHiSf+tjjM= github.com/digitalocean/godo v1.57.0 h1:uCpe0sRIZ/sJWxWDsJyBPBjUfSvxop+WHkHiSf+tjjM=
github.com/digitalocean/godo v1.57.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU= github.com/digitalocean/godo v1.57.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU=
github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v20.10.3+incompatible h1:+HS4XO73J41FpA260ztGujJ+0WibrA2TPJEnWNSyGNE= github.com/docker/docker v20.10.3+incompatible h1:+HS4XO73J41FpA260ztGujJ+0WibrA2TPJEnWNSyGNE=
@ -739,6 +741,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210223165440-c65ae3540d44 h1:3egqo0Vut6daANFm7tOXdNAa8v5/uLU+sgCJrc88Meo=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210223165440-c65ae3540d44/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=