mirror of
https://github.com/prometheus/prometheus.git
synced 2026-06-11 01:20:07 -04:00
Some checks are pending
buf.build / lint and publish (push) Waiting to run
CI / Go tests (push) Waiting to run
CI / More Go tests (push) Waiting to run
CI / Go tests for 32-bit x86 (push) Waiting to run
CI / Go tests for Prometheus upgrades and downgrades (push) Waiting to run
CI / Go tests with previous Go version (push) Waiting to run
CI / UI tests (push) Waiting to run
CI / Go tests on Windows (push) Waiting to run
CI / Mixins tests (push) Waiting to run
CI / Compliance testing (push) Waiting to run
CI / Build Prometheus for common architectures (push) Waiting to run
CI / Build Prometheus for all architectures (push) Waiting to run
CI / Report status of build Prometheus for all architectures (push) Blocked by required conditions
CI / Check generated parser (push) Waiting to run
CI / golangci-lint (push) Waiting to run
CI / fuzzing (push) Waiting to run
CI / codeql (push) Waiting to run
CI / Publish main branch artifacts (push) Blocked by required conditions
CI / Publish release artefacts (push) Blocked by required conditions
CI / Publish UI on npm Registry (push) Blocked by required conditions
govulncheck / Run govulncheck (push) Waiting to run
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
Signed-off-by: msnandhis <45960035+msnandhis@users.noreply.github.com>
279 lines
9.2 KiB
Go
279 lines
9.2 KiB
Go
// 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 scaleway
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/prometheus/common/model"
|
|
"github.com/prometheus/common/version"
|
|
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
|
|
ipam "github.com/scaleway/scaleway-sdk-go/api/ipam/v1"
|
|
"github.com/scaleway/scaleway-sdk-go/scw"
|
|
|
|
"github.com/prometheus/prometheus/discovery/refresh"
|
|
"github.com/prometheus/prometheus/discovery/targetgroup"
|
|
)
|
|
|
|
const (
|
|
instanceLabelPrefix = metaLabelPrefix + "instance_"
|
|
|
|
instanceBootTypeLabel = instanceLabelPrefix + "boot_type"
|
|
instanceHostnameLabel = instanceLabelPrefix + "hostname"
|
|
instanceIDLabel = instanceLabelPrefix + "id"
|
|
instanceImageArchLabel = instanceLabelPrefix + "image_arch"
|
|
instanceImageIDLabel = instanceLabelPrefix + "image_id"
|
|
instanceImageNameLabel = instanceLabelPrefix + "image_name"
|
|
instanceLocationClusterID = instanceLabelPrefix + "location_cluster_id"
|
|
instanceLocationHypervisorID = instanceLabelPrefix + "location_hypervisor_id"
|
|
instanceLocationNodeID = instanceLabelPrefix + "location_node_id"
|
|
instanceNameLabel = instanceLabelPrefix + "name"
|
|
instanceOrganizationLabel = instanceLabelPrefix + "organization_id"
|
|
instancePrivateIPv4Label = instanceLabelPrefix + "private_ipv4"
|
|
instanceProjectLabel = instanceLabelPrefix + "project_id"
|
|
instancePublicIPv4Label = instanceLabelPrefix + "public_ipv4"
|
|
instancePublicIPv6Label = instanceLabelPrefix + "public_ipv6"
|
|
instancePublicIPv4AddressesLabel = instanceLabelPrefix + "public_ipv4_addresses"
|
|
instancePublicIPv6AddressesLabel = instanceLabelPrefix + "public_ipv6_addresses"
|
|
instanceSecurityGroupIDLabel = instanceLabelPrefix + "security_group_id"
|
|
instanceSecurityGroupNameLabel = instanceLabelPrefix + "security_group_name"
|
|
instanceStateLabel = instanceLabelPrefix + "status"
|
|
instanceTagsLabel = instanceLabelPrefix + "tags"
|
|
instanceTypeLabel = instanceLabelPrefix + "type"
|
|
instanceZoneLabel = instanceLabelPrefix + "zone"
|
|
instanceRegionLabel = instanceLabelPrefix + "region"
|
|
)
|
|
|
|
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: conf.secretKeyForConfig(),
|
|
nameFilter: conf.NameFilter,
|
|
tagsFilter: conf.TagsFilter,
|
|
}
|
|
|
|
client, err := newScalewayHTTPClient(conf)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
profile, err := loadProfile(conf)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d.client, err = scw.NewClient(
|
|
scw.WithHTTPClient(client),
|
|
scw.WithUserAgent(version.PrometheusUserAgent()),
|
|
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) {
|
|
instanceAPI := instance.NewAPI(d.client)
|
|
ipamAPI := ipam.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 := instanceAPI.ListServers(req, scw.WithAllPages(), scw.WithContext(ctx))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
privateNICIPByID, err := privateNICIPs(ctx, ipamAPI, servers.Servers)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var targets []model.LabelSet
|
|
for _, server := range servers.Servers {
|
|
labels := model.LabelSet{
|
|
instanceBootTypeLabel: model.LabelValue(server.BootType),
|
|
instanceHostnameLabel: model.LabelValue(server.Hostname),
|
|
instanceIDLabel: model.LabelValue(server.ID),
|
|
instanceNameLabel: model.LabelValue(server.Name),
|
|
instanceOrganizationLabel: model.LabelValue(server.Organization),
|
|
instanceProjectLabel: model.LabelValue(server.Project),
|
|
instanceStateLabel: model.LabelValue(server.State),
|
|
instanceTypeLabel: model.LabelValue(server.CommercialType),
|
|
instanceZoneLabel: model.LabelValue(server.Zone.String()),
|
|
}
|
|
|
|
if server.Image != nil {
|
|
labels[instanceImageArchLabel] = model.LabelValue(server.Image.Arch)
|
|
labels[instanceImageIDLabel] = model.LabelValue(server.Image.ID)
|
|
labels[instanceImageNameLabel] = model.LabelValue(server.Image.Name)
|
|
}
|
|
|
|
if server.Location != nil {
|
|
labels[instanceLocationClusterID] = model.LabelValue(server.Location.ClusterID)
|
|
labels[instanceLocationHypervisorID] = model.LabelValue(server.Location.HypervisorID)
|
|
labels[instanceLocationNodeID] = model.LabelValue(server.Location.NodeID)
|
|
}
|
|
|
|
if server.SecurityGroup != nil {
|
|
labels[instanceSecurityGroupIDLabel] = model.LabelValue(server.SecurityGroup.ID)
|
|
labels[instanceSecurityGroupNameLabel] = model.LabelValue(server.SecurityGroup.Name)
|
|
}
|
|
|
|
if region, err := server.Zone.Region(); err == nil {
|
|
labels[instanceRegionLabel] = model.LabelValue(region.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)
|
|
}
|
|
|
|
addr := ""
|
|
if len(server.PublicIPs) > 0 {
|
|
var ipv4Addresses []string
|
|
var ipv6Addresses []string
|
|
|
|
for _, ip := range server.PublicIPs {
|
|
switch ip.Family {
|
|
case instance.ServerIPIPFamilyInet:
|
|
ipv4Addresses = append(ipv4Addresses, ip.Address.String())
|
|
case instance.ServerIPIPFamilyInet6:
|
|
ipv6Addresses = append(ipv6Addresses, ip.Address.String())
|
|
}
|
|
}
|
|
|
|
if len(ipv6Addresses) > 0 {
|
|
labels[instancePublicIPv6AddressesLabel] = model.LabelValue(
|
|
separator +
|
|
strings.Join(ipv6Addresses, separator) +
|
|
separator)
|
|
}
|
|
if len(ipv4Addresses) > 0 {
|
|
labels[instancePublicIPv4AddressesLabel] = model.LabelValue(
|
|
separator +
|
|
strings.Join(ipv4Addresses, separator) +
|
|
separator)
|
|
}
|
|
}
|
|
|
|
if server.IPv6 != nil { //nolint:staticcheck
|
|
labels[instancePublicIPv6Label] = model.LabelValue(server.IPv6.Address.String()) //nolint:staticcheck
|
|
addr = server.IPv6.Address.String() //nolint:staticcheck
|
|
}
|
|
|
|
if server.PublicIP != nil { //nolint:staticcheck
|
|
if server.PublicIP.Family != instance.ServerIPIPFamilyInet6 { //nolint:staticcheck
|
|
labels[instancePublicIPv4Label] = model.LabelValue(server.PublicIP.Address.String()) //nolint:staticcheck
|
|
}
|
|
addr = server.PublicIP.Address.String() //nolint:staticcheck
|
|
}
|
|
|
|
if server.PrivateIP != nil {
|
|
labels[instancePrivateIPv4Label] = model.LabelValue(*server.PrivateIP)
|
|
addr = *server.PrivateIP
|
|
}
|
|
|
|
if addr == "" {
|
|
for _, privateNIC := range server.PrivateNics {
|
|
if privateNIC == nil {
|
|
continue
|
|
}
|
|
if privateIP := privateNICIPByID[privateNIC.ID]; privateIP != "" {
|
|
labels[instancePrivateIPv4Label] = model.LabelValue(privateIP)
|
|
addr = privateIP
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if addr != "" {
|
|
addr := net.JoinHostPort(addr, strconv.FormatUint(uint64(d.port), 10))
|
|
labels[model.AddressLabel] = model.LabelValue(addr)
|
|
targets = append(targets, labels)
|
|
}
|
|
}
|
|
|
|
return []*targetgroup.Group{{Source: "scaleway", Targets: targets}}, nil
|
|
}
|
|
|
|
func privateNICIPs(ctx context.Context, api *ipam.API, servers []*instance.Server) (map[string]string, error) {
|
|
privateNICIDsByRegion := map[scw.Region][]string{}
|
|
for _, server := range servers {
|
|
if server.PrivateIP != nil || server.PublicIP != nil || server.IPv6 != nil { //nolint:staticcheck
|
|
continue
|
|
}
|
|
|
|
region, err := server.Zone.Region()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, privateNIC := range server.PrivateNics {
|
|
if privateNIC != nil && privateNIC.ID != "" {
|
|
privateNICIDsByRegion[region] = append(privateNICIDsByRegion[region], privateNIC.ID)
|
|
}
|
|
}
|
|
}
|
|
|
|
privateNICIPs := map[string]string{}
|
|
for region, privateNICIDs := range privateNICIDsByRegion {
|
|
ips, err := api.ListIPs(&ipam.ListIPsRequest{
|
|
Region: region,
|
|
ResourceIDs: privateNICIDs,
|
|
ResourceTypes: []ipam.ResourceType{ipam.ResourceTypeInstancePrivateNic},
|
|
}, scw.WithAllPages(), scw.WithContext(ctx))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, ip := range ips.IPs {
|
|
if ip != nil && ip.Resource != nil && !ip.IsIPv6 && ip.Address.IP != nil {
|
|
privateNICIPs[ip.Resource.ID] = ip.Address.IP.String()
|
|
}
|
|
}
|
|
}
|
|
|
|
return privateNICIPs, nil
|
|
}
|