VictoriaMetrics/lib/promscrape/discovery/hetzner/hcloud.go

191 lines
6.3 KiB
Go

package hetzner
import (
"encoding/json"
"fmt"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
// HcloudServerList represents a list of servers from Hetzner Cloud API.
type HcloudServerList struct {
Servers []HcloudServer `json:"servers"`
}
// HcloudServer represents the structure of server data.
type HcloudServer struct {
ID int `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
PublicNet PublicNet `json:"public_net,omitempty"`
PrivateNet []PrivateNet `json:"private_net,omitempty"`
ServerType ServerType `json:"server_type"`
Datacenter Datacenter `json:"datacenter"`
Image Image `json:"image"`
Labels map[string]string `json:"labels"`
}
// Datacenter represents the Hetzner datacenter.
type Datacenter struct {
Name string `json:"name"`
Location DatacenterLocation `json:"location"`
}
// DatacenterLocation represents the datacenter information.
type DatacenterLocation struct {
Name string `json:"name"`
NetworkZone string `json:"network_zone"`
}
// Image represents the image information.
type Image struct {
Name string `json:"name"`
Description string `json:"description"`
OsFlavor string `json:"os_flavor"`
OsVersion string `json:"os_version"`
}
// PublicNet represents the public network information.
type PublicNet struct {
IPv4 IPv4 `json:"ipv4"`
IPv6 IPv6 `json:"ipv6"`
}
// PrivateNet represents the private network information.
type PrivateNet struct {
ID int `json:"network"`
IP string `json:"ip"`
}
// IPv4 represents the IPv4 information.
type IPv4 struct {
IP string `json:"ip"`
}
// IPv6 represents the IPv6 information.
type IPv6 struct {
IP string `json:"ip"`
}
// ServerType represents the server type information.
type ServerType struct {
Name string `json:"name"`
Cores int `json:"cores"`
CPUType string `json:"cpu_type"`
Memory float32 `json:"memory"`
Disk int `json:"disk"`
}
// HcloudNetwork represents the hetzner cloud network information.
type HcloudNetwork struct {
Name string `json:"name"`
ID int `json:"id"`
}
// HcloudNetworksList represents the hetzner cloud networks list.
type HcloudNetworksList struct {
Networks []HcloudNetwork `json:"networks"`
}
// getHcloudServerLabels returns labels for hcloud servers obtained from the given cfg
func getHcloudServerLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
networks, err := getHcloudNetworks(cfg)
if err != nil {
return nil, err
}
servers, err := getServers(cfg)
if err != nil {
return nil, err
}
var ms []*promutils.Labels
for _, server := range servers.Servers {
ms = server.appendTargetLabels(ms, cfg.port, networks)
}
return ms, nil
}
// getHcloudNetworks returns hcloud networks obtained from the given cfg
func getHcloudNetworks(cfg *apiConfig) (*HcloudNetworksList, error) {
n, err := cfg.client.GetAPIResponse("/networks")
if err != nil {
return nil, fmt.Errorf("cannot query hcloud api for networks: %w", err)
}
networks, err := parseHcloudNetworksList(n)
if err != nil {
return nil, fmt.Errorf("cannot unmarshal HcloudServerList from %q: %w", n, err)
}
return networks, nil
}
// getServers returns hcloud servers obtained from the given cfg
func getServers(cfg *apiConfig) (*HcloudServerList, error) {
s, err := cfg.client.GetAPIResponse("/servers")
if err != nil {
return nil, fmt.Errorf("cannot query hcloud api for servers: %w", err)
}
servers, err := parseHcloudServerList(s)
if err != nil {
return nil, err
}
return servers, nil
}
// parseHcloudNetworks parses HcloudNetworksList from data.
func parseHcloudNetworksList(data []byte) (*HcloudNetworksList, error) {
var networks HcloudNetworksList
err := json.Unmarshal(data, &networks)
if err != nil {
return nil, fmt.Errorf("cannot unmarshal HcloudNetworksList from %q: %w", data, err)
}
return &networks, nil
}
// parseHcloudServerList parses HcloudServerList from data.
func parseHcloudServerList(data []byte) (*HcloudServerList, error) {
var servers HcloudServerList
err := json.Unmarshal(data, &servers)
if err != nil {
return nil, fmt.Errorf("cannot unmarshal HcloudServerList from %q: %w", data, err)
}
return &servers, nil
}
func (server *HcloudServer) appendTargetLabels(ms []*promutils.Labels, port int, networks *HcloudNetworksList) []*promutils.Labels {
addr := discoveryutils.JoinHostPort(server.PublicNet.IPv4.IP, port)
m := promutils.NewLabels(24)
m.Add("__address__", addr)
m.Add("__meta_hetzner_server_id", fmt.Sprintf("%d", server.ID))
m.Add("__meta_hetzner_server_name", server.Name)
m.Add("__meta_hetzner_server_status", server.Status)
m.Add("__meta_hetzner_public_ipv4", server.PublicNet.IPv4.IP)
m.Add("__meta_hetzner_public_ipv6_network", server.PublicNet.IPv6.IP)
m.Add("__meta_hetzner_datacenter", server.Datacenter.Name)
m.Add("__meta_hetzner_hcloud_image_name", server.Image.Name)
m.Add("__meta_hetzner_hcloud_image_description", server.Image.Description)
m.Add("__meta_hetzner_hcloud_image_os_flavor", server.Image.OsFlavor)
m.Add("__meta_hetzner_hcloud_image_os_version", server.Image.OsVersion)
m.Add("__meta_hetzner_hcloud_datacenter_location", server.Datacenter.Location.Name)
m.Add("__meta_hetzner_hcloud_datacenter_location_network_zone", server.Datacenter.Location.NetworkZone)
m.Add("__meta_hetzner_hcloud_server_type", server.ServerType.Name)
m.Add("__meta_hetzner_hcloud_cpu_cores", fmt.Sprintf("%d", server.ServerType.Cores))
m.Add("__meta_hetzner_hcloud_cpu_type", server.ServerType.CPUType)
m.Add("__meta_hetzner_hcloud_memory_size_gb", fmt.Sprintf("%d", int(server.ServerType.Memory)))
m.Add("__meta_hetzner_hcloud_disk_size_gb", fmt.Sprintf("%d", server.ServerType.Disk))
for _, privateNet := range server.PrivateNet {
for _, network := range networks.Networks {
if privateNet.ID == network.ID {
m.Add(discoveryutils.SanitizeLabelName("__meta_hetzner_hcloud_private_ipv4_"+network.Name), privateNet.IP)
}
}
}
for labelKey, labelValue := range server.Labels {
m.Add(discoveryutils.SanitizeLabelName("__meta_hetzner_hcloud_label_"+labelKey), labelValue)
m.Add(discoveryutils.SanitizeLabelName("__meta_hetzner_hcloud_labelpresent_"+labelKey), fmt.Sprintf("%t", true))
}
ms = append(ms, m)
return ms
}