Skip to content
This repository was archived by the owner on Oct 15, 2024. It is now read-only.

Commit c3ae179

Browse files
Add ELB Listener Rules object (#1193)
Co-authored-by: Philipp Trulson <[email protected]>
1 parent defb30f commit c3ae179

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

resources/elbv2-listenerrule.go

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package resources
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/aws/aws-sdk-go/aws/session"
7+
"github.com/aws/aws-sdk-go/service/elbv2"
8+
"github.com/rebuy-de/aws-nuke/v2/pkg/types"
9+
"github.com/sirupsen/logrus"
10+
)
11+
12+
var elbv2ListenerRulePageSize int64 = 400 // AWS has a limit of 100 rules per listener
13+
14+
type ELBv2ListenerRule struct {
15+
svc *elbv2.ELBV2
16+
ruleArn *string
17+
lbName *string
18+
listenerArn *string
19+
tags []*elbv2.Tag
20+
}
21+
22+
func init() {
23+
register("ELBv2ListenerRule", ListELBv2ListenerRules)
24+
}
25+
26+
func ListELBv2ListenerRules(sess *session.Session) ([]Resource, error) {
27+
svc := elbv2.New(sess)
28+
29+
// We need to retrieve ELBs then Listeners then Rules
30+
lbs := make([]*elbv2.LoadBalancer, 0)
31+
err := svc.DescribeLoadBalancersPages(
32+
nil,
33+
func(page *elbv2.DescribeLoadBalancersOutput, lastPage bool) bool {
34+
for _, elbv2 := range page.LoadBalancers {
35+
lbs = append(lbs, elbv2)
36+
}
37+
return !lastPage
38+
},
39+
)
40+
if err != nil {
41+
return nil, err
42+
}
43+
44+
// Required for batched tag retrieval later
45+
ruleArns := make([]*string, 0)
46+
ruleArnToResource := make(map[string]*ELBv2ListenerRule)
47+
48+
resources := make([]Resource, 0)
49+
for _, lb := range lbs {
50+
err := svc.DescribeListenersPages(
51+
&elbv2.DescribeListenersInput{
52+
LoadBalancerArn: lb.LoadBalancerArn,
53+
},
54+
func(page *elbv2.DescribeListenersOutput, lastPage bool) bool {
55+
for _, listener := range page.Listeners {
56+
rules, err := svc.DescribeRules(&elbv2.DescribeRulesInput{
57+
ListenerArn: listener.ListenerArn,
58+
PageSize: &elbv2ListenerRulePageSize,
59+
})
60+
if err == nil {
61+
for _, rule := range rules.Rules {
62+
// Skip default rules as they cannot be deleted
63+
if rule.IsDefault != nil && *rule.IsDefault {
64+
continue
65+
}
66+
67+
listenerRule := &ELBv2ListenerRule{
68+
svc: svc,
69+
ruleArn: rule.RuleArn,
70+
lbName: lb.LoadBalancerName,
71+
listenerArn: listener.ListenerArn,
72+
}
73+
74+
ruleArns = append(ruleArns, rule.RuleArn)
75+
resources = append(resources, listenerRule)
76+
ruleArnToResource[*rule.RuleArn] = listenerRule
77+
}
78+
} else {
79+
logrus.
80+
WithError(err).
81+
WithField("listenerArn", listener.ListenerArn).
82+
Error("Failed to list listener rules for listener")
83+
}
84+
}
85+
86+
return !lastPage
87+
},
88+
)
89+
if err != nil {
90+
logrus.
91+
WithError(err).
92+
WithField("loadBalancerArn", lb.LoadBalancerArn).
93+
Error("Failed to list listeners for load balancer")
94+
}
95+
}
96+
97+
// Tags for Rules need to be fetched separately
98+
// We can only specify up to 20 in a single call
99+
// See: https://github.com/aws/aws-sdk-go/blob/0e8c61841163762f870f6976775800ded4a789b0/service/elbv2/api.go#L5398
100+
for _, ruleChunk := range Chunk(ruleArns, 20) {
101+
tagResp, err := svc.DescribeTags(&elbv2.DescribeTagsInput{
102+
ResourceArns: ruleChunk,
103+
})
104+
if err != nil {
105+
return nil, err
106+
}
107+
for _, elbv2TagInfo := range tagResp.TagDescriptions {
108+
rule := ruleArnToResource[*elbv2TagInfo.ResourceArn]
109+
rule.tags = elbv2TagInfo.Tags
110+
}
111+
}
112+
113+
return resources, nil
114+
}
115+
116+
func (e *ELBv2ListenerRule) Remove() error {
117+
_, err := e.svc.DeleteRule(&elbv2.DeleteRuleInput{
118+
RuleArn: e.ruleArn,
119+
})
120+
if err != nil {
121+
return err
122+
}
123+
124+
return nil
125+
}
126+
127+
func (e *ELBv2ListenerRule) Properties() types.Properties {
128+
properties := types.NewProperties().
129+
Set("ARN", e.ruleArn).
130+
Set("ListenerARN", e.listenerArn).
131+
Set("LoadBalancerName", e.lbName)
132+
133+
for _, tagValue := range e.tags {
134+
properties.SetTag(tagValue.Key, tagValue.Value)
135+
}
136+
return properties
137+
}
138+
139+
func (e *ELBv2ListenerRule) String() string {
140+
return fmt.Sprintf("%s -> %s", *e.lbName, *e.ruleArn)
141+
}

resources/util.go

+18
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,21 @@ func IsAWSError(err error, code string) bool {
3636

3737
return aerr.Code() == code
3838
}
39+
40+
func Chunk[T any](slice []T, size int) [][]T {
41+
var chunks [][]T
42+
for i := 0; i < len(slice); {
43+
// Clamp the last chunk to the slice bound as necessary.
44+
end := size
45+
if l := len(slice[i:]); l < size {
46+
end = l
47+
}
48+
49+
// Set the capacity of each chunk so that appending to a chunk does not
50+
// modify the original slice.
51+
chunks = append(chunks, slice[i:i+end:i+end])
52+
i += end
53+
}
54+
55+
return chunks
56+
}

0 commit comments

Comments
 (0)