diff --git a/components/datadog/agent/ecsFargate.go b/components/datadog/agent/ecsFargate.go index 2a3ca11cb..76015047a 100644 --- a/components/datadog/agent/ecsFargate.go +++ b/components/datadog/agent/ecsFargate.go @@ -56,3 +56,38 @@ func ECSFargateLinuxContainerDefinition(e config.CommonEnvironment, image string VolumesFrom: ecs.TaskDefinitionVolumeFromArray{}, } } + +// ECSFargateWindowsContainerDefinition returns the container definition for the Windows agent running on ECS Fargate. +// Firelens is not supported. Logs could be collected if sent to cloudwatch using the `awslogs` driver. See: +// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/tutorial-deploy-fluentbit-on-windows.html +func ECSFargateWindowsContainerDefinition(e config.CommonEnvironment, image string, apiKeySSMParamName pulumi.StringInput, fakeintake *fakeintake.Fakeintake) *ecs.TaskDefinitionContainerDefinitionArgs { + if image == "" { + image = dockerAgentFullImagePath(&e, "public.ecr.aws/datadog/agent", "latest") + } + + return &ecs.TaskDefinitionContainerDefinitionArgs{ + Cpu: pulumi.IntPtr(0), + Name: pulumi.String("datadog-agent"), + Image: pulumi.String(image), + Essential: pulumi.BoolPtr(true), + Environment: append(ecs.TaskDefinitionKeyValuePairArray{ + ecs.TaskDefinitionKeyValuePairArgs{ + Name: pulumi.StringPtr("ECS_FARGATE"), + Value: pulumi.StringPtr("true"), + }, + ecs.TaskDefinitionKeyValuePairArgs{ + Name: pulumi.StringPtr("DD_CHECKS_TAG_CARDINALITY"), + Value: pulumi.StringPtr("high"), + }, + }, ecsFakeintakeAdditionalEndpointsEnv(fakeintake)...), + Secrets: ecs.TaskDefinitionSecretArray{ + ecs.TaskDefinitionSecretArgs{ + Name: pulumi.String("DD_API_KEY"), + ValueFrom: apiKeySSMParamName, + }, + }, + PortMappings: ecs.TaskDefinitionPortMappingArray{}, + VolumesFrom: ecs.TaskDefinitionVolumeFromArray{}, + WorkingDirectory: pulumi.String(`C:\`), + } +} diff --git a/components/datadog/apps/aspnetsample/ecs.go b/components/datadog/apps/aspnetsample/ecs.go new file mode 100644 index 000000000..30fed03dd --- /dev/null +++ b/components/datadog/apps/aspnetsample/ecs.go @@ -0,0 +1,118 @@ +package aspnetsample + +import ( + "github.com/DataDog/test-infra-definitions/common/config" + "github.com/DataDog/test-infra-definitions/common/utils" + fakeintakeComp "github.com/DataDog/test-infra-definitions/components/datadog/fakeintake" + "github.com/DataDog/test-infra-definitions/resources/aws" + ecsClient "github.com/DataDog/test-infra-definitions/resources/aws/ecs" + classicECS "github.com/pulumi/pulumi-aws/sdk/v5/go/aws/ecs" + "github.com/pulumi/pulumi-awsx/sdk/go/awsx/ecs" + "github.com/pulumi/pulumi-awsx/sdk/go/awsx/lb" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" +) + +type EcsFargateComponent struct { + pulumi.ResourceState +} + +func FargateAppDefinition(e aws.Environment, clusterArn pulumi.StringInput, apiKeySSMParamName pulumi.StringInput, fakeIntake *fakeintakeComp.Fakeintake, opts ...pulumi.ResourceOption) (*EcsFargateComponent, error) { + namer := e.Namer.WithPrefix("aspnetsample").WithPrefix("fg") + + opts = append(opts, e.WithProviders(config.ProviderAWS, config.ProviderAWSX)) + + EcsFargateComponent := &EcsFargateComponent{} + if err := e.Ctx.RegisterComponentResource("dd:apps", namer.ResourceName("grp"), EcsFargateComponent, opts...); err != nil { + return nil, err + } + + opts = append(opts, pulumi.Parent(EcsFargateComponent)) + + nlb, err := lb.NewNetworkLoadBalancer(e.Ctx, namer.ResourceName("lb"), &lb.NetworkLoadBalancerArgs{ + Name: e.CommonNamer.DisplayName(32, pulumi.String("aspnetsample"), pulumi.String("fg")), + SubnetIds: e.RandomSubnets(), + Internal: pulumi.BoolPtr(true), + DefaultTargetGroup: &lb.TargetGroupArgs{ + Name: e.CommonNamer.DisplayName(32, pulumi.String("aspnetsample"), pulumi.String("fg")), + Port: pulumi.IntPtr(80), + Protocol: pulumi.StringPtr("TCP"), + TargetType: pulumi.StringPtr("ip"), + VpcId: pulumi.StringPtr(e.DefaultVPCID()), + }, + Listener: &lb.ListenerArgs{ + Port: pulumi.IntPtr(80), + Protocol: pulumi.StringPtr("TCP"), + }, + }, opts...) + if err != nil { + return nil, err + } + + serverContainer := &ecs.TaskDefinitionContainerDefinitionArgs{ + Name: pulumi.String("aspnetsample"), + Image: pulumi.String("mcr.microsoft.com/dotnet/samples:aspnetapp-nanoserver-ltsc2022"), + DockerLabels: pulumi.StringMap{ + "com.datadoghq.ad.checks": pulumi.String(utils.JSONMustMarshal( + map[string]interface{}{ + "http_check": map[string]interface{}{ + "name": "aspnetsample", + "init_config": map[string]interface{}{}, + "instances": []map[string]interface{}{ + { + "url": "http://%%host%%/80", + }, + }, + }, + }, + )), + "com.datadoghq.ad.tags": pulumi.String("[\"ecs_launch_type:fargate\"]"), + }, + Cpu: pulumi.IntPtr(1024), + Memory: pulumi.IntPtr(2048), + Essential: pulumi.BoolPtr(true), + // Health check is disabled in the agent. + //DependsOn: ecs.TaskDefinitionContainerDependencyArray{ + // ecs.TaskDefinitionContainerDependencyArgs{ + // ContainerName: pulumi.String("datadog-agent"), + // Condition: pulumi.String("HEALTHY"), + // }, + //}, + PortMappings: ecs.TaskDefinitionPortMappingArray{ + ecs.TaskDefinitionPortMappingArgs{ + ContainerPort: pulumi.IntPtr(80), + HostPort: pulumi.IntPtr(80), + Protocol: pulumi.StringPtr("tcp"), + }, + }, + } + + serverTaskDef, err := ecsClient.FargateWindowsTaskDefinitionWithAgent(e, "aspnet-fg-server", pulumi.String("aspnet-fg"), 1024, 2048, map[string]ecs.TaskDefinitionContainerDefinitionArgs{"aspnetsample": *serverContainer}, apiKeySSMParamName, fakeIntake, opts...) + if err != nil { + return nil, err + } + + if _, err := ecs.NewFargateService(e.Ctx, namer.ResourceName("server"), &ecs.FargateServiceArgs{ + Cluster: clusterArn, + Name: e.CommonNamer.DisplayName(255, pulumi.String("aspnetsample"), pulumi.String("fg")), + DesiredCount: pulumi.IntPtr(1), + NetworkConfiguration: classicECS.ServiceNetworkConfigurationArgs{ + AssignPublicIp: pulumi.BoolPtr(e.ECSServicePublicIP()), + SecurityGroups: pulumi.ToStringArray(e.DefaultSecurityGroups()), + Subnets: nlb.LoadBalancer.Subnets(), + }, + TaskDefinition: serverTaskDef.TaskDefinition.Arn(), + EnableExecuteCommand: pulumi.BoolPtr(true), + ContinueBeforeSteadyState: pulumi.BoolPtr(true), + LoadBalancers: classicECS.ServiceLoadBalancerArray{ + &classicECS.ServiceLoadBalancerArgs{ + ContainerName: pulumi.String("aspnetsample"), + ContainerPort: pulumi.Int(80), + TargetGroupArn: nlb.DefaultTargetGroup.Arn(), + }, + }, + }, opts...); err != nil { + return nil, err + } + + return EcsFargateComponent, nil +} diff --git a/resources/aws/ecs/fargateService.go b/resources/aws/ecs/fargateService.go index 6caa5cbf8..ac50407af 100644 --- a/resources/aws/ecs/fargateService.go +++ b/resources/aws/ecs/fargateService.go @@ -36,6 +36,38 @@ func FargateService(e aws.Environment, name string, clusterArn pulumi.StringInpu }, utils.MergeOptions(opts, e.WithProviders(config.ProviderAWS, config.ProviderAWSX))...) } +// FargateWindowsTaskDefinitionWithAgent creates a Fargate task definition with the Datadog agent and log router containers. +// This is for Windows containers. +func FargateWindowsTaskDefinitionWithAgent( + e aws.Environment, + name string, + family pulumi.StringInput, + cpu, memory int, + containers map[string]ecs.TaskDefinitionContainerDefinitionArgs, + apiKeySSMParamName pulumi.StringInput, + fakeintake *fakeintake.Fakeintake, + opts ...pulumi.ResourceOption, +) (*ecs.FargateTaskDefinition, error) { + containers["datadog-agent"] = *agent.ECSFargateWindowsContainerDefinition(*e.CommonEnvironment, "public.ecr.aws/datadog/agent:latest", apiKeySSMParamName, fakeintake) + // aws-for-fluent-bit:windowsservercore-latest can only be used with cloudwatch logs. + + return ecs.NewFargateTaskDefinition(e.Ctx, e.Namer.ResourceName(name), &ecs.FargateTaskDefinitionArgs{ + Containers: containers, + Cpu: pulumi.StringPtr(fmt.Sprintf("%d", cpu)), + Memory: pulumi.StringPtr(fmt.Sprintf("%d", memory)), + ExecutionRole: &awsx.DefaultRoleWithPolicyArgs{ + RoleArn: pulumi.StringPtr(e.ECSTaskExecutionRole()), + }, + TaskRole: &awsx.DefaultRoleWithPolicyArgs{ + RoleArn: pulumi.StringPtr(e.ECSTaskRole()), + }, + Family: e.CommonNamer.DisplayName(255, family), + RuntimePlatform: classicECS.TaskDefinitionRuntimePlatformArgs{ + OperatingSystemFamily: pulumi.String("WINDOWS_SERVER_2022_CORE"), + }, + }, utils.MergeOptions(opts, e.WithProviders(config.ProviderAWS, config.ProviderAWSX))...) +} + func FargateTaskDefinitionWithAgent( e aws.Environment, name string, diff --git a/scenarios/aws/ecs/run.go b/scenarios/aws/ecs/run.go index 388f1bef2..e2982f0b8 100644 --- a/scenarios/aws/ecs/run.go +++ b/scenarios/aws/ecs/run.go @@ -3,6 +3,7 @@ package ecs import ( "github.com/DataDog/test-infra-definitions/common/config" "github.com/DataDog/test-infra-definitions/components/datadog/agent" + "github.com/DataDog/test-infra-definitions/components/datadog/apps/aspnetsample" "github.com/DataDog/test-infra-definitions/components/datadog/apps/cpustress" "github.com/DataDog/test-infra-definitions/components/datadog/apps/dogstatsd" "github.com/DataDog/test-infra-definitions/components/datadog/apps/nginx" @@ -155,6 +156,10 @@ func Run(ctx *pulumi.Context) error { if _, err = nginx.FargateAppDefinition(awsEnv, ecsCluster.Arn, apiKeyParam.Name, fakeIntake); err != nil { return err } + + if _, err = aspnetsample.FargateAppDefinition(awsEnv, ecsCluster.Arn, apiKeyParam.Name, fakeIntake); err != nil { + return err + } } return nil