2021-03-10 22:10:17 +08:00
// 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/instance/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
2021-10-22 16:19:38 +08:00
"github.com/prometheus/prometheus/discovery/refresh"
"github.com/prometheus/prometheus/discovery/targetgroup"
2021-03-10 22:10:17 +08:00
)
const (
instanceLabelPrefix = metaLabelPrefix + "instance_"
2021-03-12 08:03:27 +08:00
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"
2021-03-13 06:53:08 +08:00
instanceOrganizationLabel = instanceLabelPrefix + "organization_id"
2021-03-12 08:03:27 +08:00
instancePrivateIPv4Label = instanceLabelPrefix + "private_ipv4"
instanceProjectLabel = instanceLabelPrefix + "project_id"
instancePublicIPv4Label = instanceLabelPrefix + "public_ipv4"
instancePublicIPv6Label = instanceLabelPrefix + "public_ipv6"
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"
2021-03-10 22:10:17 +08:00
)
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 ,
2021-03-25 07:33:21 +08:00
secretKey : conf . secretKeyForConfig ( ) ,
2021-03-10 22:10:17 +08:00
nameFilter : conf . NameFilter ,
tagsFilter : conf . TagsFilter ,
}
2021-09-27 05:16:12 +08:00
rt , err := config . NewRoundTripperFromConfig ( conf . HTTPClientConfig , "scaleway_sd" )
2021-03-10 22:10:17 +08:00
if err != nil {
return nil , err
}
2021-03-25 07:33:21 +08:00
if conf . SecretKeyFile != "" {
rt , err = newAuthTokenFileRoundTripper ( conf . SecretKeyFile , rt )
if err != nil {
return nil , err
}
}
2021-03-10 22:10:17 +08:00
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 {
2021-04-20 02:40:14 +08:00
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 )
2021-03-12 08:03:27 +08:00
}
if region , err := server . Zone . Region ( ) ; err == nil {
labels [ instanceRegionLabel ] = model . LabelValue ( region . String ( ) )
2021-03-10 22:10:17 +08:00
}
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 )
}
2024-04-27 22:01:30 +08:00
addr := ""
2024-06-05 21:40:55 +08:00
if server . IPv6 != nil { //nolint:staticcheck see comments in https://github.com/prometheus/prometheus/pull/14212
labels [ instancePublicIPv6Label ] = model . LabelValue ( server . IPv6 . Address . String ( ) ) //nolint:staticcheck see comments in https://github.com/prometheus/prometheus/pull/14212
addr = server . IPv6 . Address . String ( ) //nolint:staticcheck see comments in https://github.com/prometheus/prometheus/pull/14212
2021-03-10 22:10:17 +08:00
}
2024-06-05 21:40:55 +08:00
if server . PublicIP != nil { //nolint:staticcheck see comments in https://github.com/prometheus/prometheus/pull/14212
labels [ instancePublicIPv4Label ] = model . LabelValue ( server . PublicIP . Address . String ( ) ) //nolint:staticcheck see comments in https://github.com/prometheus/prometheus/pull/14212
addr = server . PublicIP . Address . String ( ) //nolint:staticcheck see comments in https://github.com/prometheus/prometheus/pull/14212
2021-03-10 22:10:17 +08:00
}
if server . PrivateIP != nil {
2021-03-12 08:03:27 +08:00
labels [ instancePrivateIPv4Label ] = model . LabelValue ( * server . PrivateIP )
2024-04-27 22:01:30 +08:00
addr = * server . PrivateIP
}
2021-03-10 22:10:17 +08:00
2024-04-27 22:01:30 +08:00
if addr != "" {
addr := net . JoinHostPort ( addr , strconv . FormatUint ( uint64 ( d . port ) , 10 ) )
2021-03-10 22:10:17 +08:00
labels [ model . AddressLabel ] = model . LabelValue ( addr )
targets = append ( targets , labels )
}
}
return [ ] * targetgroup . Group { { Source : "scaleway" , Targets : targets } } , nil
}