mirror of
				https://github.com/prometheus/prometheus.git
				synced 2025-10-31 00:11:23 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			202 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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/scaleway/scaleway-sdk-go/api/baremetal/v1"
 | |
| 	"github.com/scaleway/scaleway-sdk-go/scw"
 | |
| 
 | |
| 	"github.com/prometheus/prometheus/discovery/refresh"
 | |
| 	"github.com/prometheus/prometheus/discovery/targetgroup"
 | |
| )
 | |
| 
 | |
| 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")
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if conf.SecretKeyFile != "" {
 | |
| 		rt, err = newAuthTokenFileRoundTripper(conf.SecretKeyFile, rt)
 | |
| 		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
 | |
| }
 |