Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion pkg/app/piped/executor/ecs/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package ecs

import (
"context"
"strconv"

"github.com/aws/aws-sdk-go-v2/service/ecs/types"

Expand Down Expand Up @@ -109,7 +110,12 @@ func (e *deployExecutor) ensureSync(ctx context.Context) model.StageStatus {
}

recreate := e.appCfg.QuickSync.Recreate
if !sync(ctx, &e.Input, e.platformProviderName, e.platformProviderCfg, recreate, taskDefinition, servicedefinition, primary) {
forceNewDeployment := e.appCfg.QuickSync.ForceNewDeployment

// Store force new deployment flag to metadata store.
e.Input.MetadataStore.Shared().Put(ctx, "force-new-deployment", strconv.FormatBool(forceNewDeployment))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: use a const for the key

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@t-kikuc Thanks, fixed by 025460c. Please re-approve 🙏


if !sync(ctx, &e.Input, e.platformProviderName, e.platformProviderCfg, recreate, forceNewDeployment, taskDefinition, servicedefinition, primary) {
return model.StageStatus_STAGE_FAILURE
}

Expand Down
16 changes: 10 additions & 6 deletions pkg/app/piped/executor/ecs/ecs.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,15 @@ func applyTaskDefinition(ctx context.Context, cli provider.Client, taskDefinitio
return td, nil
}

func applyServiceDefinition(ctx context.Context, cli provider.Client, serviceDefinition types.Service) (*types.Service, error) {
func applyServiceDefinition(ctx context.Context, cli provider.Client, serviceDefinition types.Service, forceNewDeployment bool) (*types.Service, error) {
found, err := cli.ServiceExists(ctx, *serviceDefinition.ClusterArn, *serviceDefinition.ServiceName)
if err != nil {
return nil, fmt.Errorf("unable to validate service name %s: %w", *serviceDefinition.ServiceName, err)
}

var service *types.Service
if found {
service, err = cli.UpdateService(ctx, serviceDefinition)
service, err = cli.UpdateService(ctx, serviceDefinition, forceNewDeployment)
if err != nil {
return nil, fmt.Errorf("failed to update ECS service %s: %w", *serviceDefinition.ServiceName, err)
}
Expand Down Expand Up @@ -291,7 +291,7 @@ func createPrimaryTaskSet(ctx context.Context, client provider.Client, service t
return nil
}

func sync(ctx context.Context, in *executor.Input, platformProviderName string, platformProviderCfg *config.PlatformProviderECSConfig, recreate bool, taskDefinition types.TaskDefinition, serviceDefinition types.Service, targetGroup *types.LoadBalancer) bool {
func sync(ctx context.Context, in *executor.Input, platformProviderName string, platformProviderCfg *config.PlatformProviderECSConfig, recreate bool, forceNewDeployment bool, taskDefinition types.TaskDefinition, serviceDefinition types.Service, targetGroup *types.LoadBalancer) bool {
client, err := provider.DefaultRegistry().Client(platformProviderName, platformProviderCfg, in.Logger)
if err != nil {
in.LogPersister.Errorf("Unable to create ECS client for the provider %s: %v", platformProviderName, err)
Expand All @@ -306,7 +306,7 @@ func sync(ctx context.Context, in *executor.Input, platformProviderName string,
}

in.LogPersister.Infof("Start applying the ECS service definition")
service, err := applyServiceDefinition(ctx, client, serviceDefinition)
service, err := applyServiceDefinition(ctx, client, serviceDefinition, forceNewDeployment)
if err != nil {
in.LogPersister.Errorf("Failed to apply service %s: %v", *serviceDefinition.ServiceName, err)
return false
Expand All @@ -330,7 +330,7 @@ func sync(ctx context.Context, in *executor.Input, platformProviderName string,
// Scale up the service tasks count back to its desired.
in.LogPersister.Infof("Scale up ECS desired tasks count back to %d", cnt)
service.DesiredCount = cnt
if _, err = client.UpdateService(ctx, *service); err != nil {
if _, err = client.UpdateService(ctx, *service, forceNewDeployment); err != nil {
in.LogPersister.Errorf("Failed to turning back service tasks: %v", err)
return false
}
Expand Down Expand Up @@ -367,7 +367,11 @@ func rollout(ctx context.Context, in *executor.Input, platformProviderName strin
}

in.LogPersister.Infof("Start applying the ECS service definition")
service, err := applyServiceDefinition(ctx, client, serviceDefinition)

// forceNewDeployment is false since this configuration only available for QuickSync strategy.
forceNewDeployment := false

service, err := applyServiceDefinition(ctx, client, serviceDefinition, forceNewDeployment)
if err != nil {
in.LogPersister.Errorf("Failed to apply service %s: %v", *serviceDefinition.ServiceName, err)
return false
Expand Down
9 changes: 8 additions & 1 deletion pkg/app/piped/executor/ecs/rollback.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,15 @@ func rollback(ctx context.Context, in *executor.Input, platformProviderName stri
return false
}

// Retrieve force new deployment flag from metadata store.
forceNewDeployment := false
val, ok := in.MetadataStore.Shared().Get("force-new-deployment")
if ok && val == "true" {
forceNewDeployment = true
}

// Rollback ECS service configuration to previous state including commit-hash of the tag.
service, err := applyServiceDefinition(ctx, client, serviceDefinition)
service, err := applyServiceDefinition(ctx, client, serviceDefinition, forceNewDeployment)
if err != nil {
in.LogPersister.Errorf("Unable to rollback ECS service %s configuration to previous stage: %v", *serviceDefinition.ServiceName, err)
return false
Expand Down
3 changes: 2 additions & 1 deletion pkg/app/piped/platformprovider/ecs/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,14 @@ func (c *client) PruneServiceTasks(ctx context.Context, service types.Service) e
return nil
}

func (c *client) UpdateService(ctx context.Context, service types.Service) (*types.Service, error) {
func (c *client) UpdateService(ctx context.Context, service types.Service, forceNewDeployment bool) (*types.Service, error) {
if service.LaunchType != "" && service.CapacityProviderStrategy != nil {
return nil, fmt.Errorf("failed to update ECS service %s: launch type and capacity provider strategy cannot be specified together", *service.ServiceName)
}
input := &ecs.UpdateServiceInput{
Cluster: service.ClusterArn,
Service: service.ServiceName,
ForceNewDeployment: forceNewDeployment,
EnableExecuteCommand: aws.Bool(service.EnableExecuteCommand),
PlacementStrategy: service.PlacementStrategy,
// TODO: Support update other properties of service.
Expand Down
2 changes: 1 addition & 1 deletion pkg/app/piped/platformprovider/ecs/ecs.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type ECS interface {
ListClusters(ctx context.Context) ([]string, error)
ServiceExists(ctx context.Context, clusterName string, servicesName string) (bool, error)
CreateService(ctx context.Context, service types.Service) (*types.Service, error)
UpdateService(ctx context.Context, service types.Service) (*types.Service, error)
UpdateService(ctx context.Context, service types.Service, forceNewDeployment bool) (*types.Service, error)
PruneServiceTasks(ctx context.Context, service types.Service) error
WaitServiceStable(ctx context.Context, service types.Service) error
GetServices(ctx context.Context, clusterName string) ([]*types.Service, error)
Expand Down
5 changes: 5 additions & 0 deletions pkg/config/application_ecs.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ type ECSSyncStageOptions struct {
// If this is set, the application may be unavailable for a short of time during the deployment.
// Default is false.
Recreate bool `json:"recreate"`
// Whether to force a new deployment or not.
// If this is set, the new service deployment will be forced to start even if the service is already in a desired state.
// This is useful when you want to update the service configuration.
// Default is false.
ForceNewDeployment bool `json:"forceNewDeployment"`
}

// ECSCanaryRolloutStageOptions contains all configurable values for a ECS_CANARY_ROLLOUT stage.
Expand Down