VictoriaMetrics/lib/promscrape/discovery/ovhcloud/common.go
Zhu Jiekun 7bb8853a5c
feature: [vmagent] Add service discovery support for OVH Cloud VPS and dedicated server (#6160)
### 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>
2024-09-30 14:42:46 +02:00

103 lines
2.8 KiB
Go

package ovhcloud
import (
"crypto/sha1"
"fmt"
"net/http"
"net/netip"
"strconv"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
)
func getAuthHeaders(cfg *apiConfig, headers http.Header, endpoint, path string) (http.Header, error) {
timestamp := getOVHTimestamp(cfg)
headers = setGeneralHeaders(cfg, headers)
headers.Set("X-Ovh-Timestamp", strconv.FormatInt(timestamp, 10))
headers.Add("X-Ovh-Consumer", cfg.consumerKey)
h := sha1.New()
h.Write([]byte(fmt.Sprintf("%s+%s+%s+%s+%s+%d",
cfg.applicationSecret,
cfg.consumerKey,
"GET",
endpoint+path,
"", // no body contained in any service discovery request, so it's set to empty by default
timestamp,
)))
headers.Set("X-Ovh-Signature", fmt.Sprintf("$1$%x", h.Sum(nil)))
return headers, nil
}
func setGeneralHeaders(cfg *apiConfig, headers http.Header) http.Header {
headers.Set("X-Ovh-Application", cfg.applicationKey)
headers.Set("Accept", "application/json")
headers.Set("User-Agent", "github.com/VictoriaMetrics/VictoriaMetrics")
return headers
}
func getServerTime(cfg *apiConfig) (*time.Time, error) {
resp, err := cfg.client.GetAPIResponseWithReqParams("/auth/time", func(req *http.Request) {
req.Header = setGeneralHeaders(cfg, req.Header)
})
if err != nil {
return nil, fmt.Errorf("failed to get server time from /auth/time: %w", err)
}
ts, err := strconv.ParseInt(string(resp), 10, 0)
if err != nil {
return nil, fmt.Errorf("parse ovh response to timestamp failed: %w", err)
}
serverTime := time.Unix(ts, 0)
return &serverTime, nil
}
// getOVHTimestamp return the server timestamp which is required by X-Ovh-Timestamp header.
// The timestamp is calculated by now() - timeDelta, where timeDelta is retrieved from /auth/time API and stored in config.
// It returns now() when server timestamp is unknown.
func getOVHTimestamp(cfg *apiConfig) int64 {
d, ok := cfg.timeDelta.Load().(time.Duration)
if ok {
return time.Now().Add(-d).Unix()
}
ovhTime, err := getServerTime(cfg)
if err != nil {
logger.Warnf("cannot get OVH server time, err: %v. using current timestamp.", err)
return time.Now().Unix()
}
d = time.Since(*ovhTime)
cfg.timeDelta.Store(d)
return time.Now().Add(-d).Unix()
}
func parseIPList(ipList []string) ([]netip.Addr, error) {
var ipAddresses []netip.Addr
for _, ip := range ipList {
ipAddr, err := netip.ParseAddr(ip)
if err != nil {
ipPrefix, err := netip.ParsePrefix(ip)
if err != nil {
return nil, fmt.Errorf("could not parse IP addresses: %s", ip)
}
if ipPrefix.IsValid() {
netmask := ipPrefix.Bits()
if netmask != 32 {
continue
}
ipAddr = ipPrefix.Addr()
}
}
if ipAddr.IsValid() && !ipAddr.IsUnspecified() {
ipAddresses = append(ipAddresses, ipAddr)
}
}
if len(ipAddresses) == 0 {
return nil, fmt.Errorf("could not parse IP addresses from ip List: %v", ipList)
}
return ipAddresses, nil
}