mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-24 03:06:48 +01:00
d1d59d6348
### Describe Your Changes related issue: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6071 #### Added - Added service discovery support for OVH Cloud: - VPS. - Dedicated server. #### Docs - `CHANGELOG.md`, `sd_configs.md`, `vmagent.md` are updated. #### Note - Useful links: - OVH Cloud VPS API: https://eu.api.ovh.com/console/#/vps~GET - OVH Cloud Dedicated server API: https://eu.api.ovh.com/console/#/dedicated/server~GET - OVH Cloud SDK: https://github.com/ovh/go-ovh - Prometheus SD: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#ovhcloud_sd_config Tested on OVH Cloud VPS and dedicated server. <img width="1722" alt="image" src="https://github.com/VictoriaMetrics/VictoriaMetrics/assets/30280396/d3f0adc8-b0ef-423e-9379-8a9b9b0792ee"> <img width="1724" alt="image" src="https://github.com/VictoriaMetrics/VictoriaMetrics/assets/30280396/18b5b730-3512-4fc0-8b2c-f2450ac550fd"> --- Signed-off-by: Jiekun <jiekun@victoriametrics.com> Co-authored-by: hagen1778 <roman@victoriametrics.com>
175 lines
5.8 KiB
Go
175 lines
5.8 KiB
Go
package ovhcloud
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/netip"
|
|
"net/url"
|
|
"path"
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
|
|
)
|
|
|
|
// vpsModel struct from API.
|
|
// See: https://eu.api.ovh.com/console/#/vps/%7BserviceName%7D~GET and getVPSDetails
|
|
type vpsModel struct {
|
|
MaximumAdditionalIP int `json:"maximumAdditionnalIp"`
|
|
Offer string `json:"offer"`
|
|
Datacenter []string `json:"datacenter"`
|
|
Vcore int `json:"vcore"`
|
|
Version string `json:"version"`
|
|
Name string `json:"name"`
|
|
Disk int `json:"disk"`
|
|
Memory int `json:"memory"`
|
|
}
|
|
|
|
// virtualPrivateServer struct from API.
|
|
// IP addresses are fetched independently.
|
|
type virtualPrivateServer struct {
|
|
IPs []netip.Addr
|
|
Zone string `json:"zone"`
|
|
Model vpsModel `json:"model"`
|
|
DisplayName string `json:"displayName"`
|
|
Cluster string `json:"cluster"`
|
|
State string `json:"state"`
|
|
Name string `json:"name"`
|
|
NetbootMode string `json:"netbootMode"`
|
|
MemoryLimit int `json:"memoryLimit"`
|
|
OfferType string `json:"offerType"`
|
|
Vcore int `json:"vcore"`
|
|
|
|
// The following fields are defined in the response but are not used during service discovery.
|
|
//Keymap []string `json:"keymap"`
|
|
//MonitoringIPBlocks []string `json:"monitoringIpBlocks"`
|
|
}
|
|
|
|
// getVPSLabels get labels for VPS.
|
|
func getVPSLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
|
|
vpsList, err := getVPSList(cfg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Attach properties to each VPS and compose vpsDetailedList
|
|
vpsDetailedList := make([]virtualPrivateServer, 0, len(vpsList))
|
|
for _, vpsName := range vpsList {
|
|
vpsDetailed, err := getVPSDetails(cfg, vpsName)
|
|
if err != nil {
|
|
logger.Errorf("getVPSDetails for %s failed, err: %v", vpsName, err)
|
|
continue
|
|
}
|
|
vpsDetailedList = append(vpsDetailedList, *vpsDetailed)
|
|
}
|
|
|
|
ms := make([]*promutils.Labels, 0, len(vpsDetailedList))
|
|
for _, server := range vpsDetailedList {
|
|
// convert IPs into string and select default IP.
|
|
var ipv4, ipv6 string
|
|
for _, ip := range server.IPs {
|
|
if ip.Is4() {
|
|
ipv4 = ip.String()
|
|
}
|
|
if ip.Is6() {
|
|
ipv6 = ip.String()
|
|
}
|
|
}
|
|
defaultIP := ipv4
|
|
if defaultIP == "" {
|
|
defaultIP = ipv6
|
|
}
|
|
|
|
m := promutils.NewLabels(21)
|
|
m.Add("__address__", defaultIP)
|
|
m.Add("instance", server.Name)
|
|
m.Add("__meta_ovhcloud_vps_offer", server.Model.Offer)
|
|
m.Add("__meta_ovhcloud_vps_datacenter", fmt.Sprintf("%+v", server.Model.Datacenter))
|
|
m.Add("__meta_ovhcloud_vps_model_vcore", fmt.Sprintf("%d", server.Model.Vcore))
|
|
m.Add("__meta_ovhcloud_vps_maximum_additional_ip", fmt.Sprintf("%d", server.Model.MaximumAdditionalIP))
|
|
m.Add("__meta_ovhcloud_vps_version", server.Model.Version)
|
|
m.Add("__meta_ovhcloud_vps_model_name", server.Model.Name)
|
|
m.Add("__meta_ovhcloud_vps_disk", fmt.Sprintf("%d", server.Model.Disk))
|
|
m.Add("__meta_ovhcloud_vps_memory", fmt.Sprintf("%d", server.Model.Memory))
|
|
m.Add("__meta_ovhcloud_vps_zone", server.Zone)
|
|
m.Add("__meta_ovhcloud_vps_display_name", server.DisplayName)
|
|
m.Add("__meta_ovhcloud_vps_cluster", server.Cluster)
|
|
m.Add("__meta_ovhcloud_vps_state", server.State)
|
|
m.Add("__meta_ovhcloud_vps_name", server.Name)
|
|
m.Add("__meta_ovhcloud_vps_netboot_mode", server.NetbootMode)
|
|
m.Add("__meta_ovhcloud_vps_memory_limit", fmt.Sprintf("%d", server.MemoryLimit))
|
|
m.Add("__meta_ovhcloud_vps_offer_type", server.OfferType)
|
|
m.Add("__meta_ovhcloud_vps_vcore", fmt.Sprintf("%d", server.Vcore))
|
|
m.Add("__meta_ovhcloud_vps_ipv4", ipv4)
|
|
m.Add("__meta_ovhcloud_vps_ipv6", ipv6)
|
|
|
|
ms = append(ms, m)
|
|
}
|
|
return ms, nil
|
|
}
|
|
|
|
// getVPSDetails get properties of a VPS.
|
|
// Also see: https://eu.api.ovh.com/console/#/vps/%7BserviceName%7D~GET
|
|
func getVPSDetails(cfg *apiConfig, vpsName string) (*virtualPrivateServer, error) {
|
|
// get properties.
|
|
reqPath := path.Join("/vps", url.QueryEscape(vpsName))
|
|
resp, err := cfg.client.GetAPIResponseWithReqParams(reqPath, func(request *http.Request) {
|
|
request.Header, _ = getAuthHeaders(cfg, request.Header, cfg.client.APIServer(), reqPath)
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("request %s error: %v", reqPath, err)
|
|
}
|
|
|
|
var vpsDetails virtualPrivateServer
|
|
if err = json.Unmarshal(resp, &vpsDetails); err != nil {
|
|
return nil, fmt.Errorf("cannot unmarshal %s response: %v", reqPath, err)
|
|
}
|
|
|
|
// get IPs for this vps.
|
|
// e.g. ["139.99.154.111","2402:1f00:8100:401::bb6"]
|
|
// Also see: https://eu.api.ovh.com/console/#/vps/%7BserviceName%7D/ips~GET
|
|
reqPath = path.Join(reqPath, "ips")
|
|
resp, err = cfg.client.GetAPIResponseWithReqParams(reqPath, func(request *http.Request) {
|
|
request.Header, _ = getAuthHeaders(cfg, request.Header, cfg.client.APIServer(), reqPath)
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("request %s error: %v", reqPath, err)
|
|
}
|
|
|
|
var ips []string
|
|
if err = json.Unmarshal(resp, &ips); err != nil {
|
|
return nil, fmt.Errorf("cannot unmarshal %s response: %v", reqPath, err)
|
|
}
|
|
|
|
// handle different IP formats
|
|
parsedIPs, err := parseIPList(ips)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// attach to details
|
|
vpsDetails.IPs = parsedIPs
|
|
|
|
return &vpsDetails, nil
|
|
}
|
|
|
|
// getVPSList list available services.
|
|
// example: ["vps-000e0e00.vps.ovh.ca", "vps-000e0e01.vps.ovh.ca"]
|
|
// Also see: https://eu.api.ovh.com/console/#/vps~GET
|
|
func getVPSList(cfg *apiConfig) ([]string, error) {
|
|
reqPath := "/vps"
|
|
resp, err := cfg.client.GetAPIResponseWithReqParams(reqPath, func(request *http.Request) {
|
|
request.Header, _ = getAuthHeaders(cfg, request.Header, cfg.client.APIServer(), reqPath)
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("request %s error: %v", reqPath, err)
|
|
}
|
|
|
|
var vpsList []string
|
|
if err = json.Unmarshal(resp, &vpsList); err != nil {
|
|
return nil, fmt.Errorf("cannot unmarshal %s response: %v", reqPath, err)
|
|
}
|
|
|
|
return vpsList, nil
|
|
}
|