Skip to content

Commit 2ca4421

Browse files
Add network command
1 parent 00b4fa8 commit 2ca4421

File tree

14 files changed

+538
-0
lines changed

14 files changed

+538
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@
1212

1313
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
1414
.glide/
15+
vendor
16+
aws-state-report
17+
*.pdf
18+
bin

Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
build: mkdir_bin build_mac build_linux build_win
2+
3+
build_mac:
4+
GOOS=darwin GOARCH=amd64 go build -o bin/aws-state-report-for-mac
5+
6+
build_linux:
7+
GOOS=linux GOARCH=amd64 go build -o bin/aws-state-report-for-linux
8+
9+
build_win:
10+
GOOS=windows GOARCH=386 go build -o bin/aws-state-report-for-win.exe
11+
12+
mkdir_bin:
13+
mkdir -p ./bin

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,16 @@
11
# aws-state-report
2+
aws-state-report export infrastructure in aws to pdf file.
3+
4+
## Usage
5+
### aws-state-report deploy
6+
```
7+
$ aws-state-report network --help
8+
NAME:
9+
aws-state-report network - export vpcs, route tables and subnets information
10+
11+
USAGE:
12+
aws-state-report network [arguments...]
13+
14+
Examples:
15+
$ aws-state-report --awsconf default network
16+
```

cmd/network.go

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"math"
6+
7+
"github.com/atsushi-ishibashi/aws-state-report/svc"
8+
"github.com/atsushi-ishibashi/aws-state-report/util"
9+
"github.com/aws/aws-sdk-go/service/ec2"
10+
"github.com/jung-kurt/gofpdf"
11+
"github.com/urfave/cli"
12+
)
13+
14+
func NewNetworkCommand() cli.Command {
15+
return cli.Command{
16+
Name: "network",
17+
Usage: "export vpcs, route tables and subnets information",
18+
Flags: []cli.Flag{},
19+
Action: func(c *cli.Context) error {
20+
if err := util.ConfigAWS(c); err != nil {
21+
return util.ErrorRed(err.Error())
22+
}
23+
mng, err := svc.NewManager()
24+
if err != nil {
25+
return util.ErrorRed(err.Error())
26+
}
27+
ntw := &Network{
28+
manager: mng,
29+
Errs: make([]error, 0),
30+
}
31+
if err := ntw.recursiveConstruct(); err != nil {
32+
return util.ErrorRed(err.Error())
33+
}
34+
return nil
35+
},
36+
}
37+
}
38+
39+
type Network struct {
40+
Vpcs []*Vpc
41+
manager *svc.Manager
42+
Errs []error
43+
}
44+
45+
func (nt *Network) recursiveConstruct() error {
46+
nt.constructVpcs().constructRouteTables().constructSubnets().associateRouteTableSubnet()
47+
fmt.Printf("%#v\n", nt.Vpcs)
48+
nt.convertPdf()
49+
return nt.flattenErrs()
50+
}
51+
52+
func (nt *Network) constructVpcs() *Network {
53+
result, err := nt.manager.FetchVpcs()
54+
if err != nil {
55+
return nt.stackError(err)
56+
}
57+
nt.Vpcs = parseDescribeVpcsOutputToVpcs(result)
58+
return nt
59+
}
60+
61+
func (nt *Network) constructRouteTables() *Network {
62+
for _, vpc := range nt.Vpcs {
63+
if result, err := nt.manager.FetchRouteTablesWithVpc(vpc.ID); err != nil {
64+
nt.stackError(err)
65+
} else {
66+
vpc.RouteTables = parseDescribeRouteTablesOutputToRouteTables(result)
67+
}
68+
}
69+
return nt
70+
}
71+
72+
func (nt *Network) constructSubnets() *Network {
73+
for _, vpc := range nt.Vpcs {
74+
if result, err := nt.manager.FetchSubnetsWithVpc(vpc.ID); err != nil {
75+
nt.stackError(err)
76+
} else {
77+
vpc.Subnets = parseDescribeSubnetsOutputToSubnets(result)
78+
}
79+
}
80+
return nt
81+
}
82+
83+
func (nt *Network) associateRouteTableSubnet() *Network {
84+
for _, vpc := range nt.Vpcs {
85+
for _, sn := range vpc.Subnets {
86+
for _, rt := range vpc.RouteTables {
87+
for _, rtas := range rt.AssociationSubnets {
88+
if rtas == sn.ID {
89+
sn.AssociatedRouteTable = rt
90+
}
91+
}
92+
}
93+
}
94+
}
95+
return nt
96+
}
97+
98+
func (nt *Network) convertPdf() {
99+
pdf := gofpdf.New("P", "mm", "A4", "")
100+
pdf.AddPage()
101+
pdf.SetFont("Arial", "", 10)
102+
for _, v := range nt.Vpcs {
103+
pdf.CellFormat(0, 10, fmt.Sprintf("%s %s", v.TagName, v.CidrBlock), "1", 0, "C", false, 0, "")
104+
pdf.Ln(-1)
105+
for _, rt := range v.RouteTables {
106+
pdf.CellFormat(95, 10, fmt.Sprintf("%s", rt.TagName), "1", 0, "C", false, 0, "")
107+
pdf.CellFormat(95, 10, "Association Subnets", "1", 0, "C", false, 0, "")
108+
pdf.Ln(-1)
109+
currentX, currentY := pdf.GetXY()
110+
var rtHeight float64
111+
for _, rtr := range rt.Routes {
112+
pdf.MoveTo(currentX, currentY+rtHeight)
113+
pdf.CellFormat(95, 10, fmt.Sprintf("%s %s", rtr.DestinationCidrBlock, rtr.Router), "RL", 0, "C", false, 0, "")
114+
rtHeight += 10.0
115+
}
116+
var snHeight float64
117+
for _, sn := range v.Subnets {
118+
if sn.AssociatedRouteTable == rt {
119+
pdf.MoveTo(currentX+95, currentY+snHeight)
120+
pdf.CellFormat(95, 10, fmt.Sprintf("%s %s", sn.TagName, sn.CidrBlock), "RL", 0, "C", false, 0, "")
121+
snHeight += 10.0
122+
}
123+
}
124+
maxHeight := math.Max(snHeight, rtHeight)
125+
pdf.MoveTo(currentX, currentY)
126+
pdf.CellFormat(0, maxHeight, "", "1", 0, "C", false, 0, "")
127+
pdf.Ln(-1)
128+
}
129+
pdf.CellFormat(0, 10, "No Association Subnets", "1", 0, "C", false, 0, "")
130+
pdf.Ln(-1)
131+
currentX, currentY := pdf.GetXY()
132+
var noaSnHeight float64
133+
for _, sn := range v.Subnets {
134+
if sn.AssociatedRouteTable == nil {
135+
pdf.CellFormat(0, 10, fmt.Sprintf("%s %s", sn.TagName, sn.CidrBlock), "LR", 0, "C", false, 0, "")
136+
pdf.Ln(-1)
137+
noaSnHeight += 10
138+
}
139+
}
140+
pdf.MoveTo(currentX, currentY)
141+
pdf.CellFormat(0, noaSnHeight, "", "1", 0, "C", false, 0, "")
142+
pdf.AddPage()
143+
}
144+
if err := pdf.OutputFileAndClose("./network.pdf"); err != nil {
145+
nt.stackError(err)
146+
}
147+
}
148+
149+
func (nt *Network) stackError(err error) *Network {
150+
nt.Errs = append(nt.Errs, err)
151+
return nt
152+
}
153+
154+
func (nt *Network) flattenErrs() error {
155+
if len(nt.Errs) == 0 {
156+
return nil
157+
}
158+
var errStr string
159+
for _, e := range nt.Errs {
160+
errStr = errStr + e.Error() + "\n"
161+
}
162+
return fmt.Errorf(errStr)
163+
}
164+
165+
func parseDescribeVpcsOutputToVpcs(output *ec2.DescribeVpcsOutput) []*Vpc {
166+
vs := make([]*Vpc, 0)
167+
for _, v := range output.Vpcs {
168+
vpc := &Vpc{
169+
ID: *v.VpcId,
170+
TagName: extractTagName(v.Tags),
171+
CidrBlock: *v.CidrBlock,
172+
}
173+
acbs := make([]string, 0)
174+
for _, cbs := range v.CidrBlockAssociationSet {
175+
acbs = append(acbs, *cbs.CidrBlock)
176+
}
177+
vpc.AssociatedCidrBlocks = acbs
178+
vs = append(vs, vpc)
179+
}
180+
return vs
181+
}
182+
183+
func parseDescribeRouteTablesOutputToRouteTables(output *ec2.DescribeRouteTablesOutput) []*RouteTable {
184+
rts := make([]*RouteTable, 0)
185+
for _, v := range output.RouteTables {
186+
rt := &RouteTable{
187+
ID: *v.RouteTableId,
188+
TagName: extractTagName(v.Tags),
189+
}
190+
rs := make([]*Route, 0)
191+
for _, r := range v.Routes {
192+
if r.DestinationCidrBlock == nil {
193+
continue
194+
}
195+
rr := &Route{
196+
DestinationCidrBlock: *r.DestinationCidrBlock,
197+
}
198+
var routerID string
199+
if r.GatewayId != nil {
200+
routerID = *r.GatewayId
201+
}
202+
if r.NatGatewayId != nil {
203+
routerID = *r.NatGatewayId
204+
}
205+
if r.VpcPeeringConnectionId != nil {
206+
routerID = *r.VpcPeeringConnectionId
207+
}
208+
rr.Router = routerID
209+
rs = append(rs, rr)
210+
}
211+
rt.Routes = rs
212+
asSubnets := make([]string, 0)
213+
for _, as := range v.Associations {
214+
if as.SubnetId != nil {
215+
asSubnets = append(asSubnets, *as.SubnetId)
216+
} else {
217+
asSubnets = append(asSubnets, "implicit")
218+
}
219+
}
220+
rt.AssociationSubnets = asSubnets
221+
rts = append(rts, rt)
222+
}
223+
return rts
224+
}
225+
226+
func parseDescribeSubnetsOutputToSubnets(output *ec2.DescribeSubnetsOutput) []*Subnet {
227+
subnets := make([]*Subnet, 0)
228+
for _, v := range output.Subnets {
229+
sn := &Subnet{
230+
ID: *v.SubnetId,
231+
TagName: extractTagName(v.Tags),
232+
CidrBlock: *v.CidrBlock,
233+
}
234+
subnets = append(subnets, sn)
235+
}
236+
return subnets
237+
}

cmd/network_model.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package cmd
2+
3+
type Vpc struct {
4+
ID string
5+
TagName string
6+
CidrBlock string
7+
AssociatedCidrBlocks []string
8+
RouteTables []*RouteTable
9+
Subnets []*Subnet
10+
}
11+
12+
type RouteTable struct {
13+
ID string
14+
TagName string
15+
Routes []*Route
16+
AssociationSubnets []string //subnet-id
17+
}
18+
19+
type Route struct {
20+
DestinationCidrBlock string
21+
Router string
22+
}
23+
24+
type Subnet struct {
25+
ID string
26+
TagName string
27+
CidrBlock string
28+
AssociatedRouteTable *RouteTable
29+
}

cmd/util.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package cmd
2+
3+
import "github.com/aws/aws-sdk-go/service/ec2"
4+
5+
func extractTagName(tags []*ec2.Tag) string {
6+
var name string
7+
for _, tg := range tags {
8+
if *tg.Key == "Name" {
9+
name = *tg.Value
10+
}
11+
}
12+
return name
13+
}

glide.lock

Lines changed: 44 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

glide.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package: github.com/atsushi-ishibashi/aws-state-report
2+
import:
3+
- package: github.com/jung-kurt/gofpdf
4+
version: ~1.0.0
5+
- package: github.com/aws/aws-sdk-go
6+
version: ~1.10.39
7+
- package: github.com/urfave/cli
8+
version: ~1.20.0

images/ec2.png

4.19 KB
Loading

images/vpc.png

6.44 KB
Loading

0 commit comments

Comments
 (0)