Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Agents read vpc-id from EC2 IMDS on auth; the server scopes subnet_primary_seeder to vpc-id with /24 fallback, exposes VPC seeder badges, and documents cross-VPC gossip via peering/TGW.
106 lines
3.3 KiB
Go
106 lines
3.3 KiB
Go
package deploy
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const ec2IMDSBase = "http://169.254.169.254/latest"
|
|
|
|
type CloudInstanceMeta struct {
|
|
VpcID string `json:"vpc_id,omitempty"`
|
|
SubnetID string `json:"subnet_id,omitempty"`
|
|
Region string `json:"region,omitempty"`
|
|
}
|
|
|
|
func (m CloudInstanceMeta) Present() bool {
|
|
return strings.TrimSpace(m.VpcID) != "" || strings.TrimSpace(m.SubnetID) != "" || strings.TrimSpace(m.Region) != ""
|
|
}
|
|
|
|
var ec2IMDSReadMeta = readEC2InstanceMetaImpl
|
|
|
|
func ReadEC2InstanceMeta() CloudInstanceMeta {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
defer cancel()
|
|
meta, _ := ec2IMDSReadMeta(ctx)
|
|
return meta
|
|
}
|
|
|
|
func readEC2InstanceMetaImpl(ctx context.Context) (CloudInstanceMeta, error) {
|
|
token, err := fetchEC2IMDSToken(ctx)
|
|
if err != nil {
|
|
return CloudInstanceMeta{}, err
|
|
}
|
|
region, _ := fetchEC2IMDSPath(ctx, token, "meta-data/placement/region")
|
|
if strings.TrimSpace(region) == "" {
|
|
az, _ := fetchEC2IMDSPath(ctx, token, "meta-data/placement/availability-zone")
|
|
az = strings.TrimSpace(az)
|
|
if len(az) > 1 {
|
|
region = az[:len(az)-1]
|
|
}
|
|
}
|
|
macs, err := fetchEC2IMDSPath(ctx, token, "meta-data/network/interfaces/macs/")
|
|
if err != nil || strings.TrimSpace(macs) == "" {
|
|
return CloudInstanceMeta{Region: strings.TrimSpace(region)}, nil
|
|
}
|
|
mac := strings.TrimSpace(strings.Split(macs, "\n")[0])
|
|
if mac == "" {
|
|
return CloudInstanceMeta{Region: strings.TrimSpace(region)}, nil
|
|
}
|
|
if !strings.HasSuffix(mac, "/") {
|
|
mac += "/"
|
|
}
|
|
base := "meta-data/network/interfaces/macs/" + mac
|
|
vpcID, _ := fetchEC2IMDSPath(ctx, token, base+"vpc-id")
|
|
subnetID, _ := fetchEC2IMDSPath(ctx, token, base+"subnet-id")
|
|
return CloudInstanceMeta{VpcID: strings.TrimSpace(vpcID), SubnetID: strings.TrimSpace(subnetID), Region: strings.TrimSpace(region)}, nil
|
|
}
|
|
|
|
func fetchEC2IMDSToken(ctx context.Context) (string, error) {
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPut, ec2IMDSBase+"/api/token", nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
req.Header.Set("X-aws-ec2-metadata-token-ttl-seconds", "60")
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != http.StatusOK {
|
|
return "", fmt.Errorf("imds token HTTP %d", resp.StatusCode)
|
|
}
|
|
body, err := io.ReadAll(io.LimitReader(resp.Body, 128))
|
|
return strings.TrimSpace(string(body)), err
|
|
}
|
|
|
|
func fetchEC2IMDSPath(ctx context.Context, token, path string) (string, error) {
|
|
path = strings.TrimPrefix(path, "/")
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, ec2IMDSBase+"/"+path, nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if token != "" {
|
|
req.Header.Set("X-aws-ec2-metadata-token", token)
|
|
}
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != http.StatusOK {
|
|
return "", fmt.Errorf("imds HTTP %d", resp.StatusCode)
|
|
}
|
|
body, err := io.ReadAll(io.LimitReader(resp.Body, 64<<10))
|
|
return strings.TrimSpace(string(body)), err
|
|
}
|
|
|
|
// ec2IMDSToken and ec2IMDSFetch are shared helpers for cloud venue probing.
|
|
func ec2IMDSToken(ctx context.Context) (string, error) { return fetchEC2IMDSToken(ctx) }
|
|
func ec2IMDSFetch(ctx context.Context, token, path string) (string, error) {
|
|
return fetchEC2IMDSPath(ctx, token, path)
|
|
} |