mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
104 lines
2.8 KiB
Go
104 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
|
||
|
}
|