diff --git a/pkg/app/piped/executor/ecs/ecs.go b/pkg/app/piped/executor/ecs/ecs.go index a97b33d233..63675cd743 100644 --- a/pkg/app/piped/executor/ecs/ecs.go +++ b/pkg/app/piped/executor/ecs/ecs.go @@ -92,6 +92,16 @@ func loadServiceDefinition(in *executor.Input, serviceDefinitionFile string, ds return types.Service{}, false } + serviceDefinition.Tags = append( + serviceDefinition.Tags, + provider.MakeTags(map[string]string{ + provider.LabelManagedBy: provider.ManagedByPiped, + provider.LabelPiped: in.PipedConfig.PipedID, + provider.LabelApplication: in.Deployment.ApplicationId, + provider.LabelCommitHash: in.Deployment.CommitHash(), + })..., + ) + in.LogPersister.Infof("Successfully loaded the ECS service definition at commit %s", ds.Revision) return serviceDefinition, true } @@ -147,6 +157,10 @@ func applyServiceDefinition(ctx context.Context, cli provider.Client, serviceDef if err != nil { return nil, fmt.Errorf("failed to update ECS service %s: %v", *serviceDefinition.ServiceName, err) } + if err := cli.TagResource(ctx, *service.ServiceArn, serviceDefinition.Tags); err != nil { + return nil, fmt.Errorf("failed to update tags of ECS service %s: %v", *serviceDefinition.ServiceName, err) + } + } else { service, err = cli.CreateService(ctx, serviceDefinition) if err != nil { @@ -172,6 +186,12 @@ func runStandaloneTask( } in.LogPersister.Infof("Start applying the ECS task definition") + tags := provider.MakeTags(map[string]string{ + provider.LabelManagedBy: provider.ManagedByPiped, + provider.LabelPiped: in.PipedConfig.PipedID, + provider.LabelApplication: in.Deployment.ApplicationId, + provider.LabelCommitHash: in.Deployment.CommitHash(), + }) td, err := applyTaskDefinition(ctx, client, taskDefinition) if err != nil { in.LogPersister.Errorf("Failed to apply ECS task definition: %v", err) @@ -184,6 +204,7 @@ func runStandaloneTask( ecsInput.ClusterArn, ecsInput.LaunchType, &ecsInput.AwsVpcConfiguration, + tags, ) if err != nil { in.LogPersister.Errorf("Failed to run ECS task: %v", err) diff --git a/pkg/app/piped/platformprovider/ecs/client.go b/pkg/app/piped/platformprovider/ecs/client.go index 105f2659c5..d439faeca9 100644 --- a/pkg/app/piped/platformprovider/ecs/client.go +++ b/pkg/app/piped/platformprovider/ecs/client.go @@ -86,13 +86,12 @@ func (c *client) CreateService(ctx context.Context, service types.Service) (*typ PlacementConstraints: service.PlacementConstraints, PlacementStrategy: service.PlacementStrategy, PlatformVersion: service.PlatformVersion, - PropagateTags: service.PropagateTags, + PropagateTags: types.PropagateTagsService, Role: service.RoleArn, SchedulingStrategy: service.SchedulingStrategy, ServiceRegistries: service.ServiceRegistries, Tags: service.Tags, } - output, err := c.ecsClient.CreateService(ctx, input) if err != nil { return nil, fmt.Errorf("failed to create ECS service %s: %w", *service.ServiceName, err) @@ -151,7 +150,7 @@ func (c *client) RegisterTaskDefinition(ctx context.Context, taskDefinition type return output.TaskDefinition, nil } -func (c *client) RunTask(ctx context.Context, taskDefinition types.TaskDefinition, clusterArn string, launchType string, awsVpcConfiguration *appconfig.ECSVpcConfiguration) error { +func (c *client) RunTask(ctx context.Context, taskDefinition types.TaskDefinition, clusterArn string, launchType string, awsVpcConfiguration *appconfig.ECSVpcConfiguration, tags []types.Tag) error { if taskDefinition.TaskDefinitionArn == nil { return fmt.Errorf("failed to run task of task family %s: no task definition provided", *taskDefinition.Family) } @@ -160,6 +159,7 @@ func (c *client) RunTask(ctx context.Context, taskDefinition types.TaskDefinitio TaskDefinition: taskDefinition.Family, Cluster: aws.String(clusterArn), LaunchType: types.LaunchType(launchType), + Tags: tags, } if len(awsVpcConfiguration.Subnets) > 0 { @@ -341,3 +341,15 @@ func (c *client) ModifyListener(ctx context.Context, listenerArn string, routing _, err := c.elbClient.ModifyListener(ctx, input) return err } + +func (c *client) TagResource(ctx context.Context, resourceArn string, tags []types.Tag) error { + input := &ecs.TagResourceInput{ + ResourceArn: aws.String(resourceArn), + Tags: tags, + } + _, err := c.ecsClient.TagResource(ctx, input) + if err != nil { + return fmt.Errorf("failed to update tag of resource %s: %w", resourceArn, err) + } + return nil +} diff --git a/pkg/app/piped/platformprovider/ecs/ecs.go b/pkg/app/piped/platformprovider/ecs/ecs.go index 4eaee15a0d..7da090b32c 100644 --- a/pkg/app/piped/platformprovider/ecs/ecs.go +++ b/pkg/app/piped/platformprovider/ecs/ecs.go @@ -19,6 +19,7 @@ import ( "path/filepath" "sync" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ecs/types" "go.uber.org/zap" "golang.org/x/sync/singleflight" @@ -26,6 +27,14 @@ import ( "github.com/pipe-cd/pipecd/pkg/config" ) +const ( + LabelManagedBy string = "pipecd-dev-managed-by" // Always be piped. + LabelPiped string = "pipecd-dev-piped" // The id of piped handling this application. + LabelApplication string = "pipecd-dev-application" // The application this resource belongs to. + LabelCommitHash string = "pipecd-dev-commit-hash" // Hash value of the deployed commit. + ManagedByPiped string = "piped" +) + // Client is wrapper of ECS client. type Client interface { ECS @@ -37,11 +46,12 @@ type ECS interface { CreateService(ctx context.Context, service types.Service) (*types.Service, error) UpdateService(ctx context.Context, service types.Service) (*types.Service, error) RegisterTaskDefinition(ctx context.Context, taskDefinition types.TaskDefinition) (*types.TaskDefinition, error) - RunTask(ctx context.Context, taskDefinition types.TaskDefinition, clusterArn string, launchType string, awsVpcConfiguration *config.ECSVpcConfiguration) error + RunTask(ctx context.Context, taskDefinition types.TaskDefinition, clusterArn string, launchType string, awsVpcConfiguration *config.ECSVpcConfiguration, tags []types.Tag) error GetPrimaryTaskSet(ctx context.Context, service types.Service) (*types.TaskSet, error) CreateTaskSet(ctx context.Context, service types.Service, taskDefinition types.TaskDefinition, targetGroup *types.LoadBalancer, scale int) (*types.TaskSet, error) DeleteTaskSet(ctx context.Context, service types.Service, taskSetArn string) error UpdateServicePrimaryTaskSet(ctx context.Context, service types.Service, taskSet types.TaskSet) (*types.TaskSet, error) + TagResource(ctx context.Context, resourceArn string, tags []types.Tag) error } type ELB interface { @@ -109,3 +119,11 @@ var defaultRegistry = ®istry{ func DefaultRegistry() Registry { return defaultRegistry } + +func MakeTags(tags map[string]string) []types.Tag { + resourceTags := make([]types.Tag, 0, len(tags)) + for key, value := range tags { + resourceTags = append(resourceTags, types.Tag{Key: aws.String(key), Value: aws.String(value)}) + } + return resourceTags +}