Files
at-container-registry/pkg/hold/metadata.go
2026-02-09 22:39:38 -06:00

69 lines
1.6 KiB
Go

package hold
import (
"context"
"encoding/json"
"fmt"
"net/http"
"time"
)
// CloudMetadata contains region info from cloud metadata service
type CloudMetadata struct {
Region string
}
// metadataEndpoint is the cloud metadata service URL. Package-level var for test override.
var metadataEndpoint = "http://169.254.169.254"
// DetectCloudMetadata queries the instance metadata service (169.254.169.254)
// Currently supports UpCloud. Others can be added via PR.
func DetectCloudMetadata(ctx context.Context) (*CloudMetadata, error) {
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
// Try UpCloud metadata format
if meta, err := detectUpCloud(ctx); err == nil {
return meta, nil
}
// Add other providers here (AWS, GCP, Azure, DigitalOcean, etc.)
// Contributors welcome!
return nil, nil // No metadata available
}
// detectUpCloud queries UpCloud's metadata service
func detectUpCloud(ctx context.Context) (*CloudMetadata, error) {
req, err := http.NewRequestWithContext(ctx, "GET", metadataEndpoint+"/metadata/v1.json", nil)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("metadata returned %d", resp.StatusCode)
}
var data struct {
CloudName string `json:"cloud_name"`
Region string `json:"region"`
}
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return nil, err
}
if data.CloudName != "upcloud" {
return nil, fmt.Errorf("not upcloud: %s", data.CloudName)
}
return &CloudMetadata{
Region: data.Region,
}, nil
}