2024-01-15 09:13:22 +00:00
|
|
|
package hetzner
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2024-01-20 14:52:41 +00:00
|
|
|
"net"
|
2024-01-15 09:13:22 +00:00
|
|
|
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
|
|
|
|
)
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// 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 := getHCloudServers(cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var ms []*promutils.Labels
|
|
|
|
for i := range servers {
|
|
|
|
ms = appendHCloudTargetLabels(ms, &servers[i], networks, cfg.port)
|
|
|
|
}
|
|
|
|
return ms, nil
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
func appendHCloudTargetLabels(ms []*promutils.Labels, server *HCloudServer, networks []HCloudNetwork, port int) []*promutils.Labels {
|
|
|
|
m := promutils.NewLabels(24)
|
|
|
|
|
|
|
|
addr := discoveryutils.JoinHostPort(server.PublicNet.IPv4.IP, port)
|
|
|
|
m.Add("__address__", addr)
|
|
|
|
|
|
|
|
m.Add("__meta_hetzner_role", "hcloud")
|
|
|
|
m.Add("__meta_hetzner_server_id", fmt.Sprintf("%d", server.ID))
|
|
|
|
m.Add("__meta_hetzner_server_name", server.Name)
|
|
|
|
m.Add("__meta_hetzner_datacenter", server.Datacenter.Name)
|
|
|
|
m.Add("__meta_hetzner_public_ipv4", server.PublicNet.IPv4.IP)
|
|
|
|
if _, n, _ := net.ParseCIDR(server.PublicNet.IPv6.IP); n != nil {
|
|
|
|
m.Add("__meta_hetzner_public_ipv6_network", n.String())
|
|
|
|
}
|
|
|
|
m.Add("__meta_hetzner_server_status", server.Status)
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
|
|
|
if server.Image != nil {
|
|
|
|
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_version", server.Image.OsVersion)
|
|
|
|
m.Add("__meta_hetzner_hcloud_image_os_flavor", server.Image.OsFlavor)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, privateNet := range server.PrivateNet {
|
|
|
|
networkID := privateNet.ID
|
|
|
|
for _, network := range networks {
|
|
|
|
if networkID == network.ID {
|
|
|
|
labelName := discoveryutils.SanitizeLabelName("__meta_hetzner_hcloud_private_ipv4_" + network.Name)
|
|
|
|
m.Add(labelName, privateNet.IP)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for labelKey, labelValue := range server.Labels {
|
|
|
|
labelName := discoveryutils.SanitizeLabelName("__meta_hetzner_hcloud_labelpresent_" + labelKey)
|
|
|
|
m.Add(labelName, "true")
|
|
|
|
|
|
|
|
labelName = discoveryutils.SanitizeLabelName("__meta_hetzner_hcloud_label_" + labelKey)
|
|
|
|
m.Add(labelName, labelValue)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms = append(ms, m)
|
|
|
|
return ms
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// getHCloudNetworks returns hcloud networks obtained from the given cfg
|
|
|
|
func getHCloudNetworks(cfg *apiConfig) ([]HCloudNetwork, error) {
|
|
|
|
// See https://docs.hetzner.cloud/#networks-get-all-networks
|
|
|
|
var networks []HCloudNetwork
|
|
|
|
page := 1
|
|
|
|
for {
|
|
|
|
path := fmt.Sprintf("/v1/networks?page=%d", page)
|
|
|
|
data, err := cfg.client.GetAPIResponse(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("cannot query hcloud api for networks: %w", err)
|
|
|
|
}
|
|
|
|
networksPage, nextPage, err := parseHCloudNetworksList(data)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
networks = append(networks, networksPage...)
|
|
|
|
if nextPage <= page {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
page = nextPage
|
|
|
|
}
|
|
|
|
return networks, nil
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
func parseHCloudNetworksList(data []byte) ([]HCloudNetwork, int, error) {
|
|
|
|
var resp HCloudNetworksList
|
|
|
|
if err := json.Unmarshal(data, &resp); err != nil {
|
|
|
|
return nil, 0, fmt.Errorf("cannot unmarshal HCloudNetworksList from %q: %w", data, err)
|
|
|
|
}
|
|
|
|
return resp.Networks, resp.Meta.Pagination.NextPage, nil
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudNetworksList represents the hetzner cloud networks list.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#networks-get-all-networks
|
|
|
|
type HCloudNetworksList struct {
|
|
|
|
Meta HCloudMeta `json:"meta"`
|
|
|
|
Networks []HCloudNetwork `json:"networks"`
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudNetwork represents the hetzner cloud network information.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#networks-get-all-networks
|
|
|
|
type HCloudNetwork struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
ID int `json:"id"`
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// getHCloudServers returns hcloud servers obtained from the given cfg
|
|
|
|
func getHCloudServers(cfg *apiConfig) ([]HCloudServer, error) {
|
|
|
|
// See https://docs.hetzner.cloud/#servers-get-all-servers
|
|
|
|
var servers []HCloudServer
|
|
|
|
page := 1
|
|
|
|
for {
|
|
|
|
path := fmt.Sprintf("/v1/servers?page=%d", page)
|
|
|
|
data, err := cfg.client.GetAPIResponse(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("cannot query hcloud api for servers: %w", err)
|
|
|
|
}
|
|
|
|
serversPage, nextPage, err := parseHCloudServerList(data)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
servers = append(servers, serversPage...)
|
|
|
|
if nextPage <= page {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
page = nextPage
|
|
|
|
}
|
|
|
|
return servers, nil
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
func parseHCloudServerList(data []byte) ([]HCloudServer, int, error) {
|
|
|
|
var resp HCloudServerList
|
|
|
|
if err := json.Unmarshal(data, &resp); err != nil {
|
|
|
|
return nil, 0, fmt.Errorf("cannot unmarshal HCloudServerList from %q: %w", data, err)
|
|
|
|
}
|
|
|
|
return resp.Servers, resp.Meta.Pagination.NextPage, nil
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudServerList represents a list of servers from Hetzner Cloud API.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#servers-get-all-servers
|
|
|
|
type HCloudServerList struct {
|
|
|
|
Meta HCloudMeta `json:"meta"`
|
|
|
|
Servers []HCloudServer `json:"servers"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// HCloudServer represents the structure of server data.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#servers-get-all-servers
|
|
|
|
type HCloudServer struct {
|
|
|
|
ID int `json:"id"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Status string `json:"status"`
|
|
|
|
PublicNet HCloudPublicNet `json:"public_net"`
|
|
|
|
PrivateNet []HCloudPrivateNet `json:"private_net"`
|
|
|
|
ServerType HCloudServerType `json:"server_type"`
|
|
|
|
Datacenter HCloudDatacenter `json:"datacenter"`
|
|
|
|
Image *HCloudImage `json:"image"`
|
|
|
|
Labels map[string]string `json:"labels"`
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudServerType represents the server type information.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#servers-get-all-servers
|
|
|
|
type HCloudServerType struct {
|
2024-01-15 09:13:22 +00:00
|
|
|
Name string `json:"name"`
|
|
|
|
Cores int `json:"cores"`
|
2024-01-15 15:11:45 +00:00
|
|
|
CPUType string `json:"cpu_type"`
|
2024-01-15 09:13:22 +00:00
|
|
|
Memory float32 `json:"memory"`
|
|
|
|
Disk int `json:"disk"`
|
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudDatacenter represents the Hetzner datacenter.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#servers-get-all-servers
|
|
|
|
type HCloudDatacenter struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Location HCloudDatacenterLocation `json:"location"`
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudDatacenterLocation represents the datacenter information.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#servers-get-all-servers
|
|
|
|
type HCloudDatacenterLocation struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
NetworkZone string `json:"network_zone"`
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudPublicNet represents the public network information.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#servers-get-all-servers
|
|
|
|
type HCloudPublicNet struct {
|
|
|
|
IPv4 HCloudIPv4 `json:"ipv4"`
|
|
|
|
IPv6 HCloudIPv6 `json:"ipv6"`
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudIPv4 represents the IPv4 information.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#servers-get-all-servers
|
|
|
|
type HCloudIPv4 struct {
|
|
|
|
IP string `json:"ip"`
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudIPv6 represents the IPv6 information.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#servers-get-all-servers
|
|
|
|
type HCloudIPv6 struct {
|
|
|
|
IP string `json:"ip"`
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudPrivateNet represents the private network information.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#servers-get-all-servers
|
|
|
|
type HCloudPrivateNet struct {
|
|
|
|
ID int `json:"network"`
|
|
|
|
IP string `json:"ip"`
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudImage represents the image information.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#servers-get-all-servers
|
|
|
|
type HCloudImage struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Description string `json:"description"`
|
|
|
|
OsFlavor string `json:"os_flavor"`
|
|
|
|
OsVersion string `json:"os_version"`
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudMeta represents hetzner cloud meta-information.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#pagination
|
|
|
|
type HCloudMeta struct {
|
|
|
|
Pagination HCloudPagination `json:"pagination"`
|
|
|
|
}
|
2024-01-15 09:13:22 +00:00
|
|
|
|
2024-01-20 14:52:41 +00:00
|
|
|
// HCloudPagination represents hetzner cloud pagination information.
|
|
|
|
//
|
|
|
|
// See https://docs.hetzner.cloud/#pagination
|
|
|
|
type HCloudPagination struct {
|
|
|
|
NextPage int `json:"next_page"`
|
2024-01-15 09:13:22 +00:00
|
|
|
}
|