Skip to content

Commit

Permalink
Add ELB Listener Rules object (rebuy-de#1193)
Browse files Browse the repository at this point in the history
Co-authored-by: Philipp Trulson <der-eismann@users.noreply.github.com>
  • Loading branch information
vboulineau and der-eismann authored Feb 29, 2024
1 parent defb30f commit c3ae179
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 0 deletions.
141 changes: 141 additions & 0 deletions resources/elbv2-listenerrule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package resources

import (
"fmt"

"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/elbv2"
"github.com/rebuy-de/aws-nuke/v2/pkg/types"
"github.com/sirupsen/logrus"
)

var elbv2ListenerRulePageSize int64 = 400 // AWS has a limit of 100 rules per listener

type ELBv2ListenerRule struct {
svc *elbv2.ELBV2
ruleArn *string
lbName *string
listenerArn *string
tags []*elbv2.Tag
}

func init() {
register("ELBv2ListenerRule", ListELBv2ListenerRules)
}

func ListELBv2ListenerRules(sess *session.Session) ([]Resource, error) {
svc := elbv2.New(sess)

// We need to retrieve ELBs then Listeners then Rules
lbs := make([]*elbv2.LoadBalancer, 0)
err := svc.DescribeLoadBalancersPages(
nil,
func(page *elbv2.DescribeLoadBalancersOutput, lastPage bool) bool {
for _, elbv2 := range page.LoadBalancers {
lbs = append(lbs, elbv2)
}
return !lastPage
},
)
if err != nil {
return nil, err
}

// Required for batched tag retrieval later
ruleArns := make([]*string, 0)
ruleArnToResource := make(map[string]*ELBv2ListenerRule)

resources := make([]Resource, 0)
for _, lb := range lbs {
err := svc.DescribeListenersPages(
&elbv2.DescribeListenersInput{
LoadBalancerArn: lb.LoadBalancerArn,
},
func(page *elbv2.DescribeListenersOutput, lastPage bool) bool {
for _, listener := range page.Listeners {
rules, err := svc.DescribeRules(&elbv2.DescribeRulesInput{
ListenerArn: listener.ListenerArn,
PageSize: &elbv2ListenerRulePageSize,
})
if err == nil {
for _, rule := range rules.Rules {
// Skip default rules as they cannot be deleted
if rule.IsDefault != nil && *rule.IsDefault {
continue
}

listenerRule := &ELBv2ListenerRule{
svc: svc,
ruleArn: rule.RuleArn,
lbName: lb.LoadBalancerName,
listenerArn: listener.ListenerArn,
}

ruleArns = append(ruleArns, rule.RuleArn)
resources = append(resources, listenerRule)
ruleArnToResource[*rule.RuleArn] = listenerRule
}
} else {
logrus.
WithError(err).
WithField("listenerArn", listener.ListenerArn).
Error("Failed to list listener rules for listener")
}
}

return !lastPage
},
)
if err != nil {
logrus.
WithError(err).
WithField("loadBalancerArn", lb.LoadBalancerArn).
Error("Failed to list listeners for load balancer")
}
}

// Tags for Rules need to be fetched separately
// We can only specify up to 20 in a single call
// See: https://github.com/aws/aws-sdk-go/blob/0e8c61841163762f870f6976775800ded4a789b0/service/elbv2/api.go#L5398
for _, ruleChunk := range Chunk(ruleArns, 20) {
tagResp, err := svc.DescribeTags(&elbv2.DescribeTagsInput{
ResourceArns: ruleChunk,
})
if err != nil {
return nil, err
}
for _, elbv2TagInfo := range tagResp.TagDescriptions {
rule := ruleArnToResource[*elbv2TagInfo.ResourceArn]
rule.tags = elbv2TagInfo.Tags
}
}

return resources, nil
}

func (e *ELBv2ListenerRule) Remove() error {
_, err := e.svc.DeleteRule(&elbv2.DeleteRuleInput{
RuleArn: e.ruleArn,
})
if err != nil {
return err
}

return nil
}

func (e *ELBv2ListenerRule) Properties() types.Properties {
properties := types.NewProperties().
Set("ARN", e.ruleArn).
Set("ListenerARN", e.listenerArn).
Set("LoadBalancerName", e.lbName)

for _, tagValue := range e.tags {
properties.SetTag(tagValue.Key, tagValue.Value)
}
return properties
}

func (e *ELBv2ListenerRule) String() string {
return fmt.Sprintf("%s -> %s", *e.lbName, *e.ruleArn)
}
18 changes: 18 additions & 0 deletions resources/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,21 @@ func IsAWSError(err error, code string) bool {

return aerr.Code() == code
}

func Chunk[T any](slice []T, size int) [][]T {
var chunks [][]T
for i := 0; i < len(slice); {
// Clamp the last chunk to the slice bound as necessary.
end := size
if l := len(slice[i:]); l < size {
end = l
}

// Set the capacity of each chunk so that appending to a chunk does not
// modify the original slice.
chunks = append(chunks, slice[i:i+end:i+end])
i += end
}

return chunks
}

0 comments on commit c3ae179

Please sign in to comment.