Skip to content

Commit

Permalink
fix(app): fix web constructs
Browse files Browse the repository at this point in the history
  • Loading branch information
briancaffey committed Nov 6, 2022
1 parent 8ebd720 commit 5d19bbd
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 18 deletions.
21 changes: 17 additions & 4 deletions src/constructs/ad-hoc/app/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Stack } from 'aws-cdk-lib';
import { CfnOutput, Stack } from 'aws-cdk-lib';
import { IVpc, ISecurityGroup } from 'aws-cdk-lib/aws-ec2';
import { Repository } from 'aws-cdk-lib/aws-ecr';
import { Cluster, EcrImage } from 'aws-cdk-lib/aws-ecs';
Expand All @@ -9,6 +9,7 @@ import { PrivateDnsNamespace } from 'aws-cdk-lib/aws-servicediscovery';
import { Construct } from 'constructs';
// import { HighestPriorityRule } from '../../internal/customResources/highestPriorityRule';
import { EcsRoles } from '../../internal/ecs/iam';
import { ManagementCommandTask } from '../../internal/ecs/management-command';
import { WebService } from '../../internal/ecs/web';

export interface AdHocAppProps {
Expand Down Expand Up @@ -113,13 +114,25 @@ export class AdHocApp extends Construct {
healthCheckPath: '/',
});

// ensure that the backend service listener rule has a higher priority than the frontend service listener rule
// backendService.node.addDependency(frontendService);

// worker service

// scheduler service

// management command task definition
const backendUpdateTask = new ManagementCommandTask(this, 'BackendUpdateTask', {
cluster,
environmentVariables,
vpc: props.vpc,
appSecurityGroup: props.appSecurityGroup,
taskRole: ecsRoles.ecsTaskRole,
executionRole: ecsRoles.taskExecutionRole,
image: backendImage,
command: ['python', 'manage.py', 'backend_update'],
containerName: 'backendUpdate',
family: 'backendUpdate',
});

// define stack output use for running the management command
new CfnOutput(this, 'backendUpdateCommand', { value: backendUpdateTask.executionScript });
}
}
96 changes: 96 additions & 0 deletions src/constructs/internal/ecs/management-command/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { RemovalPolicy, Stack } from 'aws-cdk-lib';
import { ISecurityGroup, IVpc } from 'aws-cdk-lib/aws-ec2';
import {
LogDriver,
Cluster,
ContainerImage,
FargateTaskDefinition,
} from 'aws-cdk-lib/aws-ecs';
import { Role } from 'aws-cdk-lib/aws-iam';
import {
LogGroup,
LogStream,
RetentionDays,
} from 'aws-cdk-lib/aws-logs';
import { Construct } from 'constructs';


export interface ManagementCommandTaskProps {
readonly cluster: Cluster;
readonly vpc: IVpc;
readonly cpu?: number;
readonly memorySize?: number;
readonly appSecurityGroup: ISecurityGroup;
readonly image: ContainerImage;
readonly command: string[];
readonly containerName: string;
readonly taskRole: Role;
readonly executionRole: Role;
readonly family: string;
readonly environmentVariables: { [key: string]: string };
};

export class ManagementCommandTask extends Construct {

/**
* Script to invoke run-task and send task logs to standard output
*/
public executionScript: string;

constructor(scope: Construct, id: string, props: ManagementCommandTaskProps) {
super(scope, id);

const stackName = Stack.of(this).stackName;

// define log group and logstream
const logGroupName = `/ecs/${stackName}/${props.containerName}/`;
const streamPrefix = props.containerName;
const logGroup = new LogGroup(this, 'LogGroup', {
logGroupName,
retention: RetentionDays.ONE_DAY,
removalPolicy: RemovalPolicy.DESTROY,
});

new LogStream(this, 'LogStream', {
logGroup,
logStreamName: props.containerName,
});

// task definition
const taskDefinition = new FargateTaskDefinition(this, 'TaskDefinition', {
cpu: props.cpu ?? 256,
executionRole: props.executionRole,
taskRole: props.taskRole,
family: props.family,
});

taskDefinition.addContainer(props.containerName, {
image: props.image,
command: props.command,
containerName: props.containerName,
environment: props.environmentVariables,
essential: true,
logging: LogDriver.awsLogs({
streamPrefix,
logGroup,
}),
hostname: props.containerName,
});

// this script is called once on initial setup from GitHub Actions
const executionScript = `
START_TIME=$(date +%s000)
TASK_ID=$(aws ecs run-task --cluster ${props.cluster.clusterArn} --task-definition ${taskDefinition.taskDefinitionArn} --network-configuration "awsvpcConfiguration={subnets=[${props.vpc.privateSubnets.map(x=>{x.subnetId;}).join(',')}],securityGroups=[${props.appSecurityGroup}],assignPublicIp=ENABLED}" | jq -r '.tasks[0].taskArn')
aws ecs wait tasks-stopped --tasks $TASK_ID --cluster ${props.cluster.clusterArn}
END_TIME=$(date +%s000)
aws logs get-log-events --log-group-name ${logGroupName} --log-stream-name ${streamPrefix}/${props.containerName}/\${TASK_ID##*/} --start-time $START_TIME --end-time $END_TIME | jq -r '.events[].message'
`;

this.executionScript = executionScript;

}
}
27 changes: 13 additions & 14 deletions src/constructs/internal/ecs/web/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import {
Duration,
RemovalPolicy,
} from 'aws-cdk-lib';
import { Duration, RemovalPolicy, Stack } from 'aws-cdk-lib';
import { ISecurityGroup, IVpc } from 'aws-cdk-lib/aws-ec2';
import {
// AwsLogDriver,
LogDriver,
Cluster,
ContainerImage,
Expand Down Expand Up @@ -56,19 +52,22 @@ export class WebService extends Construct {
constructor(scope: Construct, id: string, props: WebProps) {
super(scope, id);

// Getting circular dependency error when using `FargateTaskDefinition`
// https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.FargateService.html#example
const stackName = Stack.of(this).stackName;

// define log group and logstream
const logGroupName = `/ecs/${stackName}/${props.containerName}/`;
const streamPrefix = props.containerName;

// define log group and logstream
const logGroup = new LogGroup(this, 'LogGroup', {
logGroupName: `/ecs/test/${props.containerName}`,
logGroupName,
retention: RetentionDays.ONE_DAY,
removalPolicy: RemovalPolicy.DESTROY,
});

new LogStream(this, 'LogStream', {
logGroup,
logStreamName: 'web-logs',
logStreamName: props.containerName,
});

// task definition
Expand All @@ -86,14 +85,14 @@ export class WebService extends Construct {
environment: props.environmentVariables,
essential: true,
logging: LogDriver.awsLogs({
streamPrefix: 'web',
// logGroup
streamPrefix,
logGroup,
}),
portMappings: [{
containerPort: props.port,
hostPort: props.port,
}],
hostname: `stackName-${props.containerName}`,
hostname: props.containerName,
});

const useSpot = props.useSpot ?? false;
Expand All @@ -115,7 +114,7 @@ export class WebService extends Construct {
desiredCount: 1,
enableExecuteCommand: true,
securityGroups: [props.appSecurityGroup],
serviceName: `stackName-${props.containerName}`,
serviceName: `${stackName}-${props.containerName}`,
vpcSubnets: {
subnets: props.vpc.privateSubnets,
},
Expand Down Expand Up @@ -143,7 +142,7 @@ export class WebService extends Construct {
// targetGroups: [targetGroup],
conditions: [
ListenerCondition.pathPatterns(props.pathPatterns),
ListenerCondition.hostHeaders([`stackName.${props.domainName}`]),
ListenerCondition.hostHeaders([`${stackName}.${props.domainName}`]),
],
action: ListenerAction.forward([targetGroup]),
});
Expand Down

0 comments on commit 5d19bbd

Please sign in to comment.