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

Actually fetch the tags of a service #38067

Merged
merged 3 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions .changelog/38067.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
data-source/aws_ecs_service: Correctly set `tags`
```
43 changes: 24 additions & 19 deletions internal/service/ecs/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ func FindCapacityProviderByARN(ctx context.Context, conn *ecs.ECS, arn string) (
return capacityProvider, nil
}

func FindServiceByID(ctx context.Context, conn *ecs.ECS, id, cluster string) (*ecs.Service, error) {
func findServiceByTwoPartKey(ctx context.Context, conn *ecs.ECS, serviceName, clusterNameOrARN string) (*ecs.Service, error) {
input := &ecs.DescribeServicesInput{
Cluster: aws.String(cluster),
Cluster: aws.String(clusterNameOrARN),
Include: aws.StringSlice([]string{ecs.ServiceFieldTags}),
Services: aws.StringSlice([]string{id}),
Services: aws.StringSlice([]string{serviceName}),
}

return FindService(ctx, conn, input)
return findService(ctx, conn, input)
}

func FindServiceNoTagsByID(ctx context.Context, conn *ecs.ECS, id, cluster string) (*ecs.Service, error) {
Expand All @@ -73,7 +73,7 @@ func FindServiceNoTagsByID(ctx context.Context, conn *ecs.ECS, id, cluster strin
input.Cluster = aws.String(cluster)
}

return FindService(ctx, conn, input)
return findService(ctx, conn, input)
}

type expectActiveError struct {
Expand All @@ -95,7 +95,7 @@ func FindServiceByIDWaitForActive(ctx context.Context, conn *ecs.ECS, id, cluste
// Use the retry.RetryContext function instead of WaitForState() because we don't want the timeout error, if any
err := retry.RetryContext(ctx, serviceDescribeTimeout, func() *retry.RetryError {
var err error
service, err = FindServiceByID(ctx, conn, id, cluster)
service, err = findServiceByTwoPartKey(ctx, conn, id, cluster)
if tfresource.NotFound(err) {
return retry.RetryableError(err)
}
Expand All @@ -110,19 +110,26 @@ func FindServiceByIDWaitForActive(ctx context.Context, conn *ecs.ECS, id, cluste
return nil
})
if tfresource.TimedOut(err) {
service, err = FindServiceByID(ctx, conn, id, cluster)
service, err = findServiceByTwoPartKey(ctx, conn, id, cluster)
}

return service, err
}

func FindService(ctx context.Context, conn *ecs.ECS, input *ecs.DescribeServicesInput) (*ecs.Service, error) {
func findService(ctx context.Context, conn *ecs.ECS, input *ecs.DescribeServicesInput) (*ecs.Service, error) {
output, err := findServices(ctx, conn, input)

if err != nil {
return nil, err
}

return tfresource.AssertSinglePtrResult(output)
}

func findServices(ctx context.Context, conn *ecs.ECS, input *ecs.DescribeServicesInput) ([]*ecs.Service, error) {
output, err := conn.DescribeServicesWithContext(ctx, input)

if errs.IsUnsupportedOperationInPartitionError(conn.PartitionID, err) && input.Include != nil {
id := aws.StringValueSlice(input.Services)[0]
log.Printf("[WARN] failed describing ECS Service (%s) with tags: %s; retrying without tags", id, err)

input.Include = nil
output, err = conn.DescribeServicesWithContext(ctx, input)
}
Expand All @@ -135,10 +142,15 @@ func FindService(ctx context.Context, conn *ecs.ECS, input *ecs.DescribeServices
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil {
return nil, tfresource.NewEmptyResultError(input)
}

// When an ECS Service is not found by DescribeServices(), it will return a Failure struct with Reason = "MISSING"
for _, v := range output.Failures {
if aws.StringValue(v.Reason) == "MISSING" {
Expand All @@ -148,12 +160,5 @@ func FindService(ctx context.Context, conn *ecs.ECS, input *ecs.DescribeServices
}
}

if len(output.Services) == 0 {
return nil, tfresource.NewEmptyResultError(input)
}
if n := len(output.Services); n > 1 {
return nil, tfresource.NewTooManyResultsError(n, input)
}

return output.Services[0], nil
return output.Services, nil
}
46 changes: 12 additions & 34 deletions internal/service/ecs/service_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,24 @@ package ecs

import (
"context"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @SDKDataSource("aws_ecs_service")
func DataSourceService() *schema.Resource {
// @SDKDataSource("aws_ecs_service", name="Service")
// @Tags
func dataSourceService() *schema.Resource {
return &schema.Resource{
ReadWithoutTimeout: dataSourceServiceRead,

Schema: map[string]*schema.Schema{
names.AttrServiceName: {
Type: schema.TypeString,
Required: true,
},
names.AttrARN: {
Type: schema.TypeString,
Computed: true,
Expand All @@ -47,6 +43,10 @@ func DataSourceService() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
names.AttrServiceName: {
Type: schema.TypeString,
Required: true,
},
"task_definition": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -59,45 +59,23 @@ func DataSourceService() *schema.Resource {
func dataSourceServiceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).ECSConn(ctx)
ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig

clusterArn := d.Get("cluster_arn").(string)
serviceName := d.Get(names.AttrServiceName).(string)

params := &ecs.DescribeServicesInput{
Cluster: aws.String(clusterArn),
Services: []*string{aws.String(serviceName)},
}

log.Printf("[DEBUG] Reading ECS Service: %s", params)
desc, err := conn.DescribeServicesWithContext(ctx, params)
service, err := findServiceByTwoPartKey(ctx, conn, d.Get(names.AttrServiceName).(string), d.Get("cluster_arn").(string))

if err != nil {
return sdkdiag.AppendErrorf(diags, "reading ECS Service (%s): %s", serviceName, err)
}

if desc == nil || len(desc.Services) == 0 {
return sdkdiag.AppendErrorf(diags, "service with name %q in cluster %q not found", serviceName, clusterArn)
}

if len(desc.Services) > 1 {
return sdkdiag.AppendErrorf(diags, "multiple services with name %q found in cluster %q", serviceName, clusterArn)
return sdkdiag.AppendFromErr(diags, tfresource.SingularDataSourceFindError("ECS Service", err))
}

service := desc.Services[0]
d.SetId(aws.StringValue(service.ServiceArn))

d.Set(names.AttrServiceName, service.ServiceName)
d.Set(names.AttrARN, service.ServiceArn)
d.Set("cluster_arn", service.ClusterArn)
d.Set("desired_count", service.DesiredCount)
d.Set("launch_type", service.LaunchType)
d.Set("scheduling_strategy", service.SchedulingStrategy)
d.Set(names.AttrServiceName, service.ServiceName)
d.Set("task_definition", service.TaskDefinition)

if err := d.Set(names.AttrTags, KeyValueTags(ctx, service.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
return sdkdiag.AppendErrorf(diags, "setting tags: %s", err)
}
setTagsOut(ctx, service.Tags)

return diags
}
3 changes: 2 additions & 1 deletion internal/service/ecs/service_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ func TestAccECSServiceDataSource_basic(t *testing.T) {
resource.TestCheckResourceAttrPair(resourceName, "scheduling_strategy", dataSourceName, "scheduling_strategy"),
resource.TestCheckResourceAttrPair(resourceName, names.AttrName, dataSourceName, names.AttrServiceName),
resource.TestCheckResourceAttrPair(resourceName, "task_definition", dataSourceName, "task_definition"),
resource.TestCheckResourceAttrPair(resourceName, names.AttrTags, dataSourceName, names.AttrTags),
resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsPercent, dataSourceName, acctest.CtTagsPercent),
resource.TestCheckResourceAttrPair(resourceName, "tags.Name", dataSourceName, "tags.Name"),
),
},
},
Expand Down
4 changes: 3 additions & 1 deletion internal/service/ecs/service_package_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading