Skip to content

Commit

Permalink
a
Browse files Browse the repository at this point in the history
  • Loading branch information
keroxp committed Jun 26, 2024
1 parent ff3850d commit a4de284
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 24 deletions.
45 changes: 28 additions & 17 deletions canary_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,23 @@ type CanaryTarget struct {

type CanaryTask struct {
*cage
td *ecstypes.TaskDefinition
lb *ecstypes.LoadBalancer
networkConfiguration *ecstypes.NetworkConfiguration
platformVersion *string
taskArn *string
target *CanaryTarget
*CanaryTaskInput
taskArn *string
target *CanaryTarget
}

type CanaryTaskInput struct {
TaskDefinition *ecstypes.TaskDefinition
LoadBalancer *ecstypes.LoadBalancer
NetworkConfiguration *ecstypes.NetworkConfiguration
PlatformVersion *string
}

func NewCanaryTask(c *cage, input *CanaryTaskInput) *CanaryTask {
return &CanaryTask{
cage: c,
CanaryTaskInput: input,
}
}

func (c *CanaryTask) Start(ctx context.Context) error {
Expand All @@ -40,8 +51,8 @@ func (c *CanaryTask) Start(ctx context.Context) error {
startTask := &ecs.StartTaskInput{
Cluster: &c.Env.Cluster,
Group: aws.String(fmt.Sprintf("cage:canary-task:%s", c.Env.Service)),
NetworkConfiguration: c.networkConfiguration,
TaskDefinition: c.td.TaskDefinitionArn,
NetworkConfiguration: c.NetworkConfiguration,
TaskDefinition: c.TaskDefinition.TaskDefinitionArn,
ContainerInstances: []string{c.Env.CanaryInstanceArn},
}
if o, err := c.Ecs.StartTask(ctx, startTask); err != nil {
Expand All @@ -54,10 +65,10 @@ func (c *CanaryTask) Start(ctx context.Context) error {
if o, err := c.Ecs.RunTask(ctx, &ecs.RunTaskInput{
Cluster: &c.Env.Cluster,
Group: aws.String(fmt.Sprintf("cage:canary-task:%s", c.Env.Service)),
NetworkConfiguration: c.networkConfiguration,
TaskDefinition: c.td.TaskDefinitionArn,
NetworkConfiguration: c.NetworkConfiguration,
TaskDefinition: c.TaskDefinition.TaskDefinitionArn,
LaunchType: ecstypes.LaunchTypeFargate,
PlatformVersion: c.platformVersion,
PlatformVersion: c.PlatformVersion,
}); err != nil {
return err
} else {
Expand All @@ -81,7 +92,7 @@ func (c *CanaryTask) Wait(ctx context.Context) error {
}
log.Info("🤩 canary task container(s) is healthy!")
log.Infof("canary task '%s' ensured.", *c.taskArn)
if c.lb == nil {
if c.LoadBalancer == nil {
log.Infof("no load balancer is attached to service '%s'. skip registration to target group", c.Env.Service)
return c.waitForIdleDuration(ctx)
} else {
Expand Down Expand Up @@ -131,7 +142,7 @@ func (c *CanaryTask) waitForIdleDuration(ctx context.Context) error {
func (c *CanaryTask) waitUntilHealthCeheckPassed(ctx context.Context) error {
log.Infof("😷 ensuring canary task container(s) to become healthy...")
containerHasHealthChecks := map[string]struct{}{}
for _, definition := range c.td.ContainerDefinitions {
for _, definition := range c.TaskDefinition.ContainerDefinitions {
if definition.HealthCheck != nil {
containerHasHealthChecks[*definition.Name] = struct{}{}
}
Expand Down Expand Up @@ -185,8 +196,8 @@ func (c *CanaryTask) registerToTargetGroup(ctx context.Context) error {
var targetId *string
var targetPort *int32
var subnet ec2types.Subnet
for _, container := range c.td.ContainerDefinitions {
if *container.Name == *c.lb.ContainerName {
for _, container := range c.TaskDefinition.ContainerDefinitions {
if *container.Name == *c.LoadBalancer.ContainerName {
targetPort = container.PortMappings[0].HostPort
}
}
Expand Down Expand Up @@ -241,7 +252,7 @@ func (c *CanaryTask) registerToTargetGroup(ctx context.Context) error {
log.Infof("canary task was placed: instanceId = '%s', hostPort = '%d', az = '%s'", *targetId, *targetPort, *subnet.AvailabilityZone)
}
if _, err := c.Alb.RegisterTargets(ctx, &elbv2.RegisterTargetsInput{
TargetGroupArn: c.lb.TargetGroupArn,
TargetGroupArn: c.LoadBalancer.TargetGroupArn,
Targets: []elbv2types.TargetDescription{{
AvailabilityZone: subnet.AvailabilityZone,
Id: targetId,
Expand All @@ -251,7 +262,7 @@ func (c *CanaryTask) registerToTargetGroup(ctx context.Context) error {
return err
}
c.target = &CanaryTarget{
targetGroupArn: c.lb.TargetGroupArn,
targetGroupArn: c.LoadBalancer.TargetGroupArn,
targetId: targetId,
targetPort: targetPort,
availabilityZone: subnet.AvailabilityZone,
Expand Down
45 changes: 45 additions & 0 deletions canary_task_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package cage_test

import (
"context"
"testing"

"github.com/aws/aws-sdk-go-v2/aws"
ecstypes "github.com/aws/aws-sdk-go-v2/service/ecs/types"
"github.com/golang/mock/gomock"
cage "github.com/loilo-inc/canarycage"
"github.com/loilo-inc/canarycage/mocks/mock_awsiface"
"github.com/loilo-inc/canarycage/test"
"github.com/loilo-inc/canarycage/timeout"
"github.com/stretchr/testify/assert"
)

func TestCanaryTask_Stop(t *testing.T) {
t.Run("shold stop task even if deregister task failed", func(t *testing.T) {
ctrl := gomock.NewController(t)
ecsmock := mock_awsiface.NewMockEcsClient(ctrl)
albmock := mock_awsiface.NewMockAlbClient(ctrl)
mocker := test.NewMockContext()

Check failure on line 22 in canary_task_test.go

View workflow job for this annotation

GitHub Actions / test

mocker declared and not used
env := test.DefaultEnvars()
c := &cage.CageExport{
Input: &cage.Input{
Env: env,
Alb: albmock,
Ecs: ecsmock,
},
Timeout: timeout.Default,
}
task := cage.NewCanaryTask(c, &cage.CanaryTaskInput{
LoadBalancer: &ecstypes.LoadBalancer{
ContainerName: aws.String("container"),
ContainerPort: aws.Int32(80),
TargetGroupArn: aws.String("target-group-arn"),
},
TaskDefinition: &ecstypes.TaskDefinition{
TaskDefinitionArn: aws.String("task-definition-arn"),
},
})
err := task.Stop(context.TODO())
assert.NoError(t, err)
})
}
19 changes: 12 additions & 7 deletions rollout.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (c *cage) RollOut(ctx context.Context, input *RollOutInput) (*RollOutResult
}
log.Infof("starting canary task...")
canaryTasks, startCanaryTaskErr := c.StartCanaryTasks(ctx, nextTaskDefinition, input)
// ensure canary task stopped after rolling out either success or failure
// ensure canary tasks stopped after rolling out either success or failure
defer func() {
_ = recover()
eg := errgroup.Group{}
Expand Down Expand Up @@ -148,18 +148,23 @@ func (c *cage) StartCanaryTasks(
}
var results []*CanaryTask
if len(loadBalancers) == 0 {
task := &CanaryTask{
c, nextTaskDefinition, nil, networkConfiguration, platformVersion, nil, nil,
}
task := NewCanaryTask(c, &CanaryTaskInput{
TaskDefinition: nextTaskDefinition,
NetworkConfiguration: networkConfiguration,
PlatformVersion: platformVersion,
})
results = append(results, task)
if err := task.Start(ctx); err != nil {
return results, err
}
} else {
for _, lb := range loadBalancers {
task := &CanaryTask{
c, nextTaskDefinition, &lb, networkConfiguration, platformVersion, nil, nil,
}
task := NewCanaryTask(c, &CanaryTaskInput{
TaskDefinition: nextTaskDefinition,
LoadBalancer: &lb,
NetworkConfiguration: networkConfiguration,
PlatformVersion: platformVersion,
})
results = append(results, task)
if err := task.Start(ctx); err != nil {
return results, err
Expand Down
2 changes: 2 additions & 0 deletions timeout/timeout.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ type manager struct {
DefaultTimeout time.Duration
}

var Default = NewManager(10*time.Minute, &Input{})

func NewManager(
defaultTimeout time.Duration,
input *Input,
Expand Down

0 comments on commit a4de284

Please sign in to comment.