This repository was archived by the owner on Feb 14, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.go
170 lines (149 loc) · 4.12 KB
/
main.go
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package main
import (
"bytes"
"flag"
"fmt"
"html/template"
"io"
"net"
"net/http"
"os"
"sort"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
)
type EC2Instance struct {
InstanceId string
PrivateDnsName string
PrivateIpAddress string
PublicDnsName string
PublicIpAddress string
}
func main() {
var (
showInstanceID = flag.Bool("instance-id", false, "show EC2 instance ID")
showPrivateDNS = flag.Bool("private-dns", false, "show private DNS name")
showPrivateIP = flag.Bool("private-ip", false, "show private IP address")
showPublicDNS = flag.Bool("public-dns", false, "show public DNS name")
showPublicIP = flag.Bool("public-ip", false, "show public IP address")
region = flag.String("region", "", "set AWS region")
format = flag.String("format", "{{.PrivateIpAddress}}", "alternate format in Go template syntax")
join = flag.String("join", "\n", "separator string for concatenating results")
limit = flag.Int("limit", 0, "limit number of results")
output = flag.String("output", "", "write results to given file")
)
flag.Parse()
switch {
case *showInstanceID:
*format = "{{.InstanceId}}"
case *showPrivateDNS:
*format = "{{.PrivateDnsName}}"
case *showPrivateIP:
*format = "{{.PrivateIpAddress}}"
case *showPublicDNS:
*format = "{{.PublicDnsName}}"
case *showPublicIP:
*format = "{{.PublicIpAddress}}"
}
tmpl, err := template.New("main").Parse(*format)
if err != nil {
abort("%s", err)
}
filters := map[string]string{
// Only show running EC2 instances by default
"instance-state-name": "running",
}
for _, arg := range flag.Args() {
parts := strings.SplitN(arg, "=", 2)
if len(parts) != 2 {
abort("format of filter must be key=value")
}
filters[parts[0]] = parts[1]
}
instances, err := findInstances(filters, *region)
if err != nil {
abort("%s", err)
}
var lines []string
for _, i := range instances {
var out bytes.Buffer
if err := tmpl.Execute(&out, i); err != nil {
abort("%s", err)
}
if s := out.String(); len(s) > 0 {
lines = append(lines, s)
}
}
var w io.Writer = os.Stdout
if *output != "" {
f, err := os.Create(*output)
if err != nil {
abort("%s", err)
}
defer f.Close()
w = f
}
if len(lines) > 0 {
sort.Sort(Lines(lines))
maxLines := len(lines)
if *limit > 0 && *limit < maxLines {
maxLines = *limit
}
fmt.Fprintln(w, strings.Join(lines[:maxLines], *join))
}
}
func findInstances(filters map[string]string, region string) ([]EC2Instance, error) {
var ec2Filters []*ec2.Filter
for k, v := range filters {
ec2Filters = append(ec2Filters, &ec2.Filter{
Name: aws.String(k),
Values: aws.StringSlice([]string{v}),
})
}
var instances []EC2Instance
fn := func(output *ec2.DescribeInstancesOutput, last bool) bool {
for _, r := range output.Reservations {
for _, i := range r.Instances {
instances = append(instances, EC2Instance{
InstanceId: aws.StringValue(i.InstanceId),
PrivateDnsName: aws.StringValue(i.PrivateDnsName),
PrivateIpAddress: aws.StringValue(i.PrivateIpAddress),
PublicDnsName: aws.StringValue(i.PublicDnsName),
PublicIpAddress: aws.StringValue(i.PublicIpAddress),
})
}
}
return !last
}
config := aws.NewConfig().WithHTTPClient(&http.Client{Timeout: 30 * time.Second})
if region != "" {
config.WithRegion(region)
}
sess, err := session.NewSession(config)
if err != nil {
return nil, err
}
svc := ec2.New(sess)
if err := svc.DescribeInstancesPages(&ec2.DescribeInstancesInput{Filters: ec2Filters}, fn); err != nil {
return nil, err
}
return instances, nil
}
func abort(format string, a ...interface{}) {
fmt.Fprintf(os.Stderr, "error: "+format+"\n", a...)
os.Exit(1)
}
type Lines []string
func (l Lines) Len() int { return len(l) }
func (l Lines) Less(i, j int) bool {
// Compare octets if lines are IP addresses
if a, b := net.ParseIP(l[i]), net.ParseIP(l[j]); a != nil && b != nil {
return bytes.Compare(a, b) < 0
}
// Otherwise, use string comparison
return l[i] < l[j]
}
func (l Lines) Swap(i, j int) { l[i], l[j] = l[j], l[i] }