feat: Fargate

This commit is contained in:
Zakaria
2026-10-02 09:53:45 -04:00
parent 7f08f5b668
commit 2d8ff50a99
27 changed files with 574 additions and 35 deletions
@@ -0,0 +1,93 @@
import {describe, expect, test} from 'bun:test'
import {CreateServiceCommand, DeleteServiceCommand, DescribeServicesCommand, DescribeTasksCommand, ListClustersCommand, ListServicesCommand, ListTasksCommand, type ECSClient} from '@aws-sdk/client-ecs'
import {DescribeLoadBalancersCommand, DescribeTargetGroupsCommand, DescribeTargetHealthCommand, type ElasticLoadBalancingV2Client} from '@aws-sdk/client-elastic-load-balancing-v2'
import {AwsEcsAdapter} from './AwsEcsAdapter'
import {AwsFargateAdapter} from './AwsFargateAdapter'
const cluster = 'orders-cluster'
describe('AwsEcsAdapter', () => {
test('lists EC2 and Fargate services with task, IP target, and ALB health', async () => {
const ecs = {async send(command: object) {
if (command instanceof ListClustersCommand) return {clusterArns: [cluster]}
if (command instanceof ListServicesCommand) return {serviceArns: ['orders', 'fargate']}
if (command instanceof DescribeServicesCommand) return {services: [
{serviceName: 'orders', serviceArn: 'arn:aws:ecs:us-east-1:000000000000:service/orders', launchType: 'EC2', status: 'ACTIVE', desiredCount: 2, runningCount: 1, pendingCount: 1, taskDefinition: 'orders:4'},
{serviceName: 'fargate', serviceArn: 'arn:aws:ecs:us-east-1:000000000000:service/fargate', launchType: 'FARGATE', status: 'ACTIVE', desiredCount: 1, runningCount: 1, taskDefinition: 'fargate:1', networkConfiguration: {awsvpcConfiguration: {subnets: ['subnet-1'], securityGroups: ['sg-1'], assignPublicIp: 'ENABLED'}}, loadBalancers: [{targetGroupArn: 'tg-1', containerName: 'app', containerPort: 8080}]},
]}
if (command instanceof ListTasksCommand) return {taskArns: ['task-1']}
if (command instanceof DescribeTasksCommand) return {tasks: [{taskArn: 'task-1', lastStatus: 'RUNNING', healthStatus: 'HEALTHY', connectivity: 'CONNECTED'}]}
return {}
}} as unknown as ECSClient
const elb = {async send(command: object) {
if (command instanceof DescribeTargetGroupsCommand) return {TargetGroups: [{TargetType: 'ip', LoadBalancerArns: ['alb-1']}]}
if (command instanceof DescribeTargetHealthCommand) return {TargetHealthDescriptions: [{Target: {Id: '10.0.1.5', Port: 8080}, TargetHealth: {State: 'healthy'}}]}
if (command instanceof DescribeLoadBalancersCommand) return {LoadBalancers: [{DNSName: 'orders.example.test', Scheme: 'internet-facing', State: {Code: 'active'}}]}
return {}
}} as unknown as ElasticLoadBalancingV2Client
const services = await new AwsEcsAdapter(ecs, elb).list()
expect(services).toHaveLength(2)
expect(services[0]).toMatchObject({metadata: {launchType: 'EC2', tasks: [{healthStatus: 'HEALTHY'}]}})
expect(services[1]).toMatchObject({metadata: {launchType: 'FARGATE', networkConfiguration: {subnets: ['subnet-1']}, loadBalancers: [{targetType: 'ip', targets: [{state: 'healthy'}], endpoints: [{dnsName: 'orders.example.test', state: 'active'}]}]}})
})
test('creates an awsvpc Fargate service and force deletes it', async () => {
const sent: object[] = []
const ecs = {async send(command: object) {
sent.push(command)
if (command instanceof CreateServiceCommand) return {service: {serviceName: 'orders', serviceArn: 'arn:aws:ecs:us-east-1:000000000000:service/orders', launchType: 'FARGATE', status: 'ACTIVE', desiredCount: 1, runningCount: 0, taskDefinition: 'orders:1'}}
if (command instanceof ListTasksCommand) return {taskArns: []}
return {}
}} as unknown as ECSClient
const elb = {async send() { return {} }} as unknown as ElasticLoadBalancingV2Client
const adapter = new AwsEcsAdapter(ecs, elb)
await adapter.create({values: {cluster, serviceName: 'orders', taskDefinition: 'orders:1', launchType: 'FARGATE', subnets: 'subnet-1, subnet-2', securityGroups: 'sg-1', assignPublicIp: 'ENABLED'}})
await adapter.delete(`${cluster}|orders`)
expect((sent[0] as CreateServiceCommand).input).toMatchObject({cluster, serviceName: 'orders', launchType: 'FARGATE', networkConfiguration: {awsvpcConfiguration: {subnets: ['subnet-1', 'subnet-2'], securityGroups: ['sg-1'], assignPublicIp: 'ENABLED'}}})
expect((sent.at(-1) as DeleteServiceCommand).input).toEqual({cluster, service: 'orders', force: true})
})
test('does not present stale inactive counts as running', async () => {
const ecs = {async send(command: object) {
if (command instanceof DescribeServicesCommand) return {services: [{serviceName: 'orders', status: 'INACTIVE', desiredCount: 2, runningCount: 2, pendingCount: 1, deployments: [{desiredCount: 2, runningCount: 2}]}]}
return {}
}} as unknown as ECSClient
const elb = {async send() { return {} }} as unknown as ElasticLoadBalancingV2Client
const service = await new AwsEcsAdapter(ecs, elb).get(`${cluster}|orders`)
expect(service).toMatchObject({metadata: {inactive: true, desiredCount: 0, runningCount: 0, pendingCount: 0, deployments: [{desiredCount: 0, runningCount: 0}]}})
})
test('Fargate adapter lists and creates only Fargate services', async () => {
const sent: object[] = []
const ecs = {async send(command: object) {
sent.push(command)
if (command instanceof ListClustersCommand) return {clusterArns: [cluster]}
if (command instanceof ListServicesCommand) return {serviceArns: ['ec2', 'fargate']}
if (command instanceof DescribeServicesCommand) return {services: [
{serviceName: 'ec2', launchType: 'EC2', status: 'ACTIVE'},
{serviceName: 'fargate', launchType: 'FARGATE', status: 'ACTIVE'},
]}
if (command instanceof CreateServiceCommand) return {service: {serviceName: 'created', launchType: 'FARGATE', status: 'ACTIVE'}}
if (command instanceof ListTasksCommand) return {taskArns: []}
return {}
}} as unknown as ECSClient
const elb = {async send() { return {} }} as unknown as ElasticLoadBalancingV2Client
const adapter = new AwsFargateAdapter(new AwsEcsAdapter(ecs, elb))
const services = await adapter.list()
const created = await adapter.create({values: {cluster, serviceName: 'created', taskDefinition: 'created:1', launchType: 'EC2', subnets: 'subnet-1'}})
expect(services).toHaveLength(1)
expect(services[0]).toMatchObject({service: 'fargate', name: 'fargate', metadata: {launchType: 'FARGATE'}})
expect(created).toMatchObject({service: 'fargate', metadata: {launchType: 'FARGATE'}})
expect(sent.find((command) => command instanceof CreateServiceCommand)).toMatchObject({input: {launchType: 'FARGATE'}})
expect(adapter.schema().fields.find((field) => field.name === 'launchType')).toBeUndefined()
expect(adapter.schema().fields.find((field) => field.name === 'subnets')).toMatchObject({required: true})
})
})