2022-05-20 05:57:23 -07:00
|
|
|
// Copyright 2022 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 ionos
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/go-kit/log"
|
|
|
|
ionoscloud "github.com/ionos-cloud/sdk-go/v6"
|
|
|
|
"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/prometheus/prometheus/util/strutil"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
serverLabelPrefix = metaLabelPrefix + "server_"
|
|
|
|
|
|
|
|
serverAvailabilityZoneLabel = serverLabelPrefix + "availability_zone"
|
|
|
|
serverBootCDROMIDLabel = serverLabelPrefix + "boot_cdrom_id"
|
|
|
|
serverBootImageIDLabel = serverLabelPrefix + "boot_image_id"
|
|
|
|
serverBootVolumeIDLabel = serverLabelPrefix + "boot_volume_id"
|
|
|
|
serverCPUFamilyLabel = serverLabelPrefix + "cpu_family"
|
|
|
|
serverIDLabel = serverLabelPrefix + "id"
|
|
|
|
serverIPLabel = serverLabelPrefix + "ip"
|
|
|
|
serverLifecycleLabel = serverLabelPrefix + "lifecycle"
|
|
|
|
serverNameLabel = serverLabelPrefix + "name"
|
|
|
|
serverNICIPLabelPrefix = serverLabelPrefix + "nic_ip_"
|
|
|
|
serverServersIDLabel = serverLabelPrefix + "servers_id"
|
|
|
|
serverStateLabel = serverLabelPrefix + "state"
|
|
|
|
serverTypeLabel = serverLabelPrefix + "type"
|
|
|
|
|
|
|
|
nicDefaultName = "unnamed"
|
|
|
|
)
|
|
|
|
|
|
|
|
type serverDiscovery struct {
|
|
|
|
*refresh.Discovery
|
|
|
|
client *ionoscloud.APIClient
|
|
|
|
port int
|
|
|
|
datacenterID string
|
|
|
|
}
|
|
|
|
|
2023-04-12 04:05:41 -07:00
|
|
|
func newServerDiscovery(conf *SDConfig, _ log.Logger) (*serverDiscovery, error) {
|
2022-05-20 05:57:23 -07:00
|
|
|
d := &serverDiscovery{
|
|
|
|
port: conf.Port,
|
|
|
|
datacenterID: conf.DatacenterID,
|
|
|
|
}
|
|
|
|
|
|
|
|
rt, err := config.NewRoundTripperFromConfig(conf.HTTPClientConfig, "ionos_sd")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Username, password and token are set via http client config.
|
|
|
|
cfg := ionoscloud.NewConfiguration("", "", "", conf.ionosEndpoint)
|
|
|
|
cfg.HTTPClient = &http.Client{
|
|
|
|
Transport: rt,
|
|
|
|
Timeout: time.Duration(conf.RefreshInterval),
|
|
|
|
}
|
|
|
|
cfg.UserAgent = fmt.Sprintf("Prometheus/%s", version.Version)
|
|
|
|
|
|
|
|
d.client = ionoscloud.NewAPIClient(cfg)
|
|
|
|
|
|
|
|
return d, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *serverDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|
|
|
api := d.client.ServersApi
|
|
|
|
|
|
|
|
servers, _, err := api.DatacentersServersGet(ctx, d.datacenterID).
|
|
|
|
Depth(3).
|
|
|
|
Execute()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var targets []model.LabelSet
|
|
|
|
for _, server := range *servers.Items {
|
|
|
|
var ips []string
|
|
|
|
ipsByNICName := make(map[string][]string)
|
|
|
|
|
|
|
|
if server.Entities != nil && server.Entities.Nics != nil {
|
|
|
|
for _, nic := range *server.Entities.Nics.Items {
|
|
|
|
nicName := nicDefaultName
|
|
|
|
if name := nic.Properties.Name; name != nil {
|
|
|
|
nicName = *name
|
|
|
|
}
|
|
|
|
|
|
|
|
nicIPs := *nic.Properties.Ips
|
|
|
|
ips = append(nicIPs, ips...)
|
|
|
|
ipsByNICName[nicName] = append(nicIPs, ipsByNICName[nicName]...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If a server has no IP addresses, it's being dropped from the targets.
|
|
|
|
if len(ips) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
addr := net.JoinHostPort(ips[0], strconv.FormatUint(uint64(d.port), 10))
|
|
|
|
labels := model.LabelSet{
|
|
|
|
model.AddressLabel: model.LabelValue(addr),
|
|
|
|
serverAvailabilityZoneLabel: model.LabelValue(*server.Properties.AvailabilityZone),
|
|
|
|
serverCPUFamilyLabel: model.LabelValue(*server.Properties.CpuFamily),
|
|
|
|
serverServersIDLabel: model.LabelValue(*servers.Id),
|
|
|
|
serverIDLabel: model.LabelValue(*server.Id),
|
|
|
|
serverIPLabel: model.LabelValue(join(ips, metaLabelSeparator)),
|
|
|
|
serverLifecycleLabel: model.LabelValue(*server.Metadata.State),
|
|
|
|
serverNameLabel: model.LabelValue(*server.Properties.Name),
|
|
|
|
serverStateLabel: model.LabelValue(*server.Properties.VmState),
|
|
|
|
serverTypeLabel: model.LabelValue(*server.Properties.Type),
|
|
|
|
}
|
|
|
|
|
|
|
|
for nicName, nicIPs := range ipsByNICName {
|
|
|
|
name := serverNICIPLabelPrefix + strutil.SanitizeLabelName(nicName)
|
|
|
|
labels[model.LabelName(name)] = model.LabelValue(join(nicIPs, metaLabelSeparator))
|
|
|
|
}
|
|
|
|
|
|
|
|
if server.Properties.BootCdrom != nil {
|
|
|
|
labels[serverBootCDROMIDLabel] = model.LabelValue(*server.Properties.BootCdrom.Id)
|
|
|
|
}
|
|
|
|
|
|
|
|
if server.Properties.BootVolume != nil {
|
|
|
|
labels[serverBootVolumeIDLabel] = model.LabelValue(*server.Properties.BootVolume.Id)
|
|
|
|
}
|
|
|
|
|
|
|
|
if server.Entities != nil && server.Entities.Volumes != nil {
|
|
|
|
volumes := *server.Entities.Volumes.Items
|
|
|
|
if len(volumes) > 0 {
|
|
|
|
image := volumes[0].Properties.Image
|
|
|
|
if image != nil {
|
|
|
|
labels[serverBootImageIDLabel] = model.LabelValue(*image)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
targets = append(targets, labels)
|
|
|
|
}
|
|
|
|
|
|
|
|
return []*targetgroup.Group{{Source: "ionos", Targets: targets}}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// join returns strings.Join with additional separators at beginning and end.
|
|
|
|
func join(elems []string, sep string) string {
|
|
|
|
return sep + strings.Join(elems, sep) + sep
|
|
|
|
}
|