forked from pwaller/associate-eip
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
125 lines (98 loc) · 2.93 KB
/
main.go
File metadata and controls
125 lines (98 loc) · 2.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package main
import (
"context"
"io"
"log"
"os"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
"github.com/aws/aws-sdk-go-v2/service/ec2"
)
func Metadata(imdsClient *imds.Client, path string) (string, error) {
metadataOutput, err := imdsClient.GetMetadata(context.Background(), &imds.GetMetadataInput{Path: path})
if err != nil {
return "", err
}
defer metadataOutput.Content.Close()
metadataOutputBytes, err := io.ReadAll(metadataOutput.Content)
if err != nil {
return "", err
}
return string(metadataOutputBytes), nil
}
// Returns current IP address via metadata endpoint or "" on error.
func MyIP(imdsClient *imds.Client) string {
ip, _ := Metadata(imdsClient, "public-ipv4")
return ip
}
func WaitForIP(imdsClient *imds.Client, target string) bool {
const MAX = 120 // Maximum number of seconds to wait
for i := 0; i < MAX; i++ {
ip := MyIP(imdsClient)
if ip == target {
log.Printf("IP updated!: %q", ip)
return true
}
log.Printf("Waiting for IP address update: %q", ip)
time.Sleep(1 * time.Second)
}
return false
}
func ThisInstanceID(imdsClient *imds.Client) (string, error) {
return Metadata(imdsClient, "instance-id")
}
func ThisAvailabilityZone(imdsClient *imds.Client) (string, error) {
result, err := Metadata(imdsClient, "placement/availability-zone")
if err == nil {
result = result[:len(result)-1]
}
return result, err
}
func main() {
log.SetFlags(0)
args := os.Args[1:]
if len(args) < 1 {
log.Fatalf("usage: %s <PublicIP>", os.Args[0])
}
publicIP := args[0]
cfg, err := config.LoadDefaultConfig(context.Background())
if err != nil {
log.Fatalf("Unable to load AWS config: %v", err)
}
imdsClient := imds.NewFromConfig(cfg)
thisInstanceID, err := ThisInstanceID(imdsClient)
if err != nil {
log.Fatalf("Unable to determine instance id: %v", err)
}
thisAvailabilityZone, err := ThisAvailabilityZone(imdsClient)
if err != nil {
log.Fatalf("Unable to determine availability zone: %v", err)
}
log.Println("InstanceID:", thisInstanceID, "AZ:", thisAvailabilityZone)
cfg.Region = thisAvailabilityZone
svc := ec2.NewFromConfig(cfg)
desc, err := svc.DescribeAddresses(context.Background(), &ec2.DescribeAddressesInput{
PublicIps: []string{(publicIP)},
})
if err != nil {
log.Fatalf("Unable to describe EIPs: %v", err)
}
if len(desc.Addresses) != 1 {
log.Fatalf("Expected exactly 1 address, got %v", len(desc.Addresses))
}
allocation := desc.Addresses[0]
resp, err := svc.AssociateAddress(context.Background(), &ec2.AssociateAddressInput{
InstanceId: &thisInstanceID,
AllowReassociation: aws.Bool(true),
AllocationId: allocation.AllocationId,
})
if err != nil {
log.Fatalf("Unable to associate allocation: %v", err)
}
log.Println("Associated:", *resp.AssociationId)
if !WaitForIP(imdsClient, publicIP) {
log.Fatal("Failed to see public IP update in a timely fashion.")
}
}