Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ECS): enable selection of listener rules #4668

Merged
Merged
15 changes: 15 additions & 0 deletions pkg/app/piped/executor/ecs/ecs.go
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,21 @@ func routing(ctx context.Context, in *executor.Input, platformProviderName strin
return false
}

currListenerRuleArns, err := client.GetListenerRuleArns(ctx, currListenerArns)
if err != nil {
in.LogPersister.Errorf("Failed to get current active listener rule: %v", err)
return false
}

if len(currListenerRuleArns) > 0 {
if err := client.ModifyRules(ctx, currListenerRuleArns, routingTrafficCfg); err != nil {
in.LogPersister.Errorf("Failed to routing traffic to PRIMARY/CANARY variants: %v", err)
return false
}
khanhtc1202 marked this conversation as resolved.
Show resolved Hide resolved

return true
}

if err := client.ModifyListeners(ctx, currListenerArns, routingTrafficCfg); err != nil {
in.LogPersister.Errorf("Failed to routing traffic to PRIMARY/CANARY variants: %v", err)
return false
Expand Down
17 changes: 16 additions & 1 deletion pkg/app/piped/executor/ecs/rollback.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,23 @@ func rollback(ctx context.Context, in *executor.Input, platformProviderName stri
return false
}

currListenerRuleArns, err := client.GetListenerRuleArns(ctx, currListenerArns)
if err != nil {
in.LogPersister.Errorf("Failed to get current active listener rule: %v", err)
return false
}

if len(currListenerRuleArns) > 0 {
if err := client.ModifyRules(ctx, currListenerRuleArns, routingTrafficCfg); err != nil {
in.LogPersister.Errorf("Failed to routing traffic to PRIMARY/CANARY variants: %v", err)
return false
}
khanhtc1202 marked this conversation as resolved.
Show resolved Hide resolved

return true
}

if err := client.ModifyListeners(ctx, currListenerArns, routingTrafficCfg); err != nil {
in.LogPersister.Errorf("Failed to routing traffic to PRIMARY variant: %v", err)
in.LogPersister.Errorf("Failed to routing traffic to PRIMARY/CANARY variants: %v", err)
return false
}
}
Expand Down
110 changes: 108 additions & 2 deletions pkg/app/piped/platformprovider/ecs/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"errors"
"fmt"
"strings"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
Expand Down Expand Up @@ -417,6 +418,30 @@ func (c *client) GetListenerArns(ctx context.Context, targetGroup types.LoadBala
return arns, nil
}

func (c *client) GetListenerRuleArns(ctx context.Context, listenerArns []string) ([]string, error) {
var ruleArns []string

// Fetch all rules by listeners
for _, listenerArn := range listenerArns {
input := &elasticloadbalancingv2.DescribeRulesInput{
ListenerArn: aws.String(listenerArn),
}
output, err := c.elbClient.DescribeRules(ctx, input)
if err != nil {
return nil, err
}
for _, rule := range output.Rules {
ruleArns = append(ruleArns, *rule.RuleArn)
}
}

if len(ruleArns) == 0 {
return nil, platformprovider.ErrNotFound
}

return ruleArns, nil
}

func (c *client) getLoadBalancerArn(ctx context.Context, targetGroupArn string) (string, error) {
input := &elasticloadbalancingv2.DescribeTargetGroupsInput{
TargetGroupArns: []string{targetGroupArn},
Expand All @@ -437,6 +462,19 @@ func (c *client) ModifyListeners(ctx context.Context, listenerArns []string, rou
return fmt.Errorf("invalid listener configuration: requires 2 target groups")
}

// Describe the rule to get current actions
describelistenerOutput, err := c.elbClient.DescribeRules(ctx, &elasticloadbalancingv2.DescribeRulesInput{
RuleArns: listenerArns,
})
if err != nil {
return fmt.Errorf("error describing listener %v: %w", strings.Join(listenerArns, ", "), err)
}

// No rules found, nothing to modify
if len(describelistenerOutput.Rules) == 0 {
return fmt.Errorf("no listener found for ARN: %s", strings.Join(listenerArns, ", "))
}

modifyListener := func(ctx context.Context, listenerArn string) error {
input := &elasticloadbalancingv2.ModifyListenerInput{
ListenerArn: aws.String(listenerArn),
Expand All @@ -463,13 +501,81 @@ func (c *client) ModifyListeners(ctx context.Context, listenerArns []string, rou
}

for _, listener := range listenerArns {
if err := modifyListener(ctx, listener); err != nil {
return err
// Check if the current action type is forward
for _, rule := range describelistenerOutput.Rules {
for _, action := range rule.Actions {
if action.Type == elbtypes.ActionTypeEnumForward {
// Call modifyListenerRule only if action type is forward
if err := modifyListener(ctx, listener); err != nil {
return err
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will delete all other rules of a given listener in case that listener contains rules of type ActionTypeEnumForward ? 🤔 So this code change means nothing, I guess. wdyt? @moko-poi

Copy link
Contributor Author

@moko-poi moko-poi Nov 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@khanhtc1202
2650922
Thank you for your review.
I have made the necessary adjustments to the ModifyListeners and ModifyRules functions to address the concerns. Now, these functions only modify actions of type ActionTypeEnumForward and preserve all other action types, ensuring that existing listener and rule configurations are not inadvertently altered.

}
}
return nil
}

func (c *client) ModifyRules(ctx context.Context, listenerRuleArns []string, routingTrafficCfg RoutingTrafficConfig) error {
if len(routingTrafficCfg) != 2 {
return fmt.Errorf("invalid listener configuration: requires 2 target groups")
}

// Describe the rule to get current actions
describeRulesOutput, err := c.elbClient.DescribeRules(ctx, &elasticloadbalancingv2.DescribeRulesInput{
RuleArns: listenerRuleArns,
})
if err != nil {
return fmt.Errorf("error describing listener rule %v: %w", strings.Join(listenerRuleArns, ", "), err)
}

// No rules found, nothing to modify
if len(describeRulesOutput.Rules) == 0 {
return fmt.Errorf("no rules found for ARN: %s", strings.Join(listenerRuleArns, ", "))
}

modifyListenerRule := func(ctx context.Context, listenerRuleArn string) error {
input := &elasticloadbalancingv2.ModifyRuleInput{
RuleArn: aws.String(listenerRuleArn),
Actions: []elbtypes.Action{
{
Type: elbtypes.ActionTypeEnumForward,
ForwardConfig: &elbtypes.ForwardActionConfig{
TargetGroups: []elbtypes.TargetGroupTuple{
{
TargetGroupArn: aws.String(routingTrafficCfg[0].TargetGroupArn),
Weight: aws.Int32(int32(routingTrafficCfg[0].Weight)),
},
{
TargetGroupArn: aws.String(routingTrafficCfg[1].TargetGroupArn),
Weight: aws.Int32(int32(routingTrafficCfg[1].Weight)),
},
},
},
},
},
}
_, err := c.elbClient.ModifyRule(ctx, input)
return err
}

for _, ruleArn := range listenerRuleArns {
// Check if the current action type is forward
for _, rule := range describeRulesOutput.Rules {
for _, action := range rule.Actions {
if action.Type == elbtypes.ActionTypeEnumForward {
// Call modifyListenerRule only if action type is forward
if err := modifyListenerRule(ctx, ruleArn); err != nil {
return err
}
}
}
}
}

return nil
}

func (c *client) TagResource(ctx context.Context, resourceArn string, tags []types.Tag) error {
input := &ecs.TagResourceInput{
ResourceArn: aws.String(resourceArn),
Expand Down
2 changes: 2 additions & 0 deletions pkg/app/piped/platformprovider/ecs/ecs.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ type ECS interface {

type ELB interface {
GetListenerArns(ctx context.Context, targetGroup types.LoadBalancer) ([]string, error)
GetListenerRuleArns(ctx context.Context, listenerArns []string) ([]string, error)
ModifyListeners(ctx context.Context, listenerArns []string, routingTrafficCfg RoutingTrafficConfig) error
ModifyRules(ctx context.Context, listenerRuleArns []string, routingTrafficCfg RoutingTrafficConfig) error
khanhtc1202 marked this conversation as resolved.
Show resolved Hide resolved
}

// Registry holds a pool of aws client wrappers.
Expand Down
Loading