Elect one fleet torrent seeder per AWS VPC via IMDS cloud_instance_meta.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
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.
This commit is contained in:
106
agent/deploy/cloud_instance_meta.go
Normal file
106
agent/deploy/cloud_instance_meta.go
Normal file
@@ -0,0 +1,106 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user