Skip to content

Commit db7c8dd

Browse files
authored
Merge pull request #53 from supabase-community/refactor-cfn-parameter
feat: Add HighAvailability option
2 parents 4a9e4a2 + e60780d commit db7c8dd

File tree

5 files changed

+415
-543
lines changed

5 files changed

+415
-543
lines changed

src/ecs-patterns.ts

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as cdk from 'aws-cdk-lib';
2+
import { ScalableTarget, CfnScalableTarget, CfnScalingPolicy } from 'aws-cdk-lib/aws-applicationautoscaling';
23
import * as ec2 from 'aws-cdk-lib/aws-ec2';
34
import * as ecs from 'aws-cdk-lib/aws-ecs';
45
import { NetworkLoadBalancedTaskImageOptions } from 'aws-cdk-lib/aws-ecs-patterns';
@@ -8,7 +9,6 @@ import * as logs from 'aws-cdk-lib/aws-logs';
89
import * as cloudMap from 'aws-cdk-lib/aws-servicediscovery';
910
import { Construct } from 'constructs';
1011
import { AuthProvider } from './supabase-auth-provider';
11-
import { SupabaseDatabase } from './supabase-db';
1212
import { FargateStack } from './supabase-stack';
1313

1414
interface SupabaseTaskImageOptions extends NetworkLoadBalancedTaskImageOptions {
@@ -30,6 +30,7 @@ export interface BaseFargateServiceProps {
3030
export interface AutoScalingFargateServiceProps extends BaseFargateServiceProps {
3131
minTaskCount?: number;
3232
maxTaskCount?: number;
33+
highAvailability?: cdk.CfnCondition;
3334
}
3435

3536
export interface TargetGroupProps {
@@ -162,55 +163,50 @@ export class BaseFargateService extends Construct {
162163
}
163164

164165
export class AutoScalingFargateService extends BaseFargateService {
165-
readonly cfnParameters: {
166-
taskSize: cdk.CfnParameter;
167-
minTaskCount: cdk.CfnParameter;
168-
maxTaskCount: cdk.CfnParameter;
169-
};
166+
readonly taskSize: cdk.CfnParameter;
167+
170168
constructor(scope: FargateStack, id: string, props: AutoScalingFargateServiceProps) {
171169
super(scope, id, props);
172170

173-
const { minTaskCount, maxTaskCount } = props;
174-
175-
this.cfnParameters = {
176-
taskSize: new cdk.CfnParameter(this, 'TaskSize', {
177-
description: 'Fargare task size',
178-
type: 'String',
179-
default: 'micro',
180-
allowedValues: ['micro', 'small', 'medium', 'large', 'xlarge', '2xlarge', '4xlarge'],
181-
}),
182-
minTaskCount: new cdk.CfnParameter(this, 'MinTaskCount', {
183-
description: 'Minimum fargate task count',
184-
type: 'Number',
185-
default: (typeof minTaskCount == 'undefined') ? 1 : minTaskCount,
186-
minValue: 0,
187-
}),
188-
maxTaskCount: new cdk.CfnParameter(this, 'MaxTaskCount', {
189-
description: 'Maximum fargate task count',
190-
type: 'Number',
191-
default: (typeof maxTaskCount == 'undefined') ? 20 : maxTaskCount,
192-
minValue: 0,
193-
}),
194-
};
195-
196-
const cpu = scope.taskSizeMapping.findInMap(this.cfnParameters.taskSize.valueAsString, 'cpu');
197-
const memory = scope.taskSizeMapping.findInMap(this.cfnParameters.taskSize.valueAsString, 'memory');
198-
199-
(this.service.taskDefinition.node.defaultChild as ecs.CfnTaskDefinition).addPropertyOverride('Cpu', cpu);
200-
(this.service.taskDefinition.node.defaultChild as ecs.CfnTaskDefinition).addPropertyOverride('Memory', memory);
201-
202-
const serviceDisabled = new cdk.CfnCondition(this, 'ServiceDisabled', { expression: cdk.Fn.conditionEquals(this.cfnParameters.minTaskCount, '0') });
203-
(this.service.node.defaultChild as ecs.CfnService).addPropertyOverride('DesiredCount', cdk.Fn.conditionIf(serviceDisabled.logicalId, 0, cdk.Aws.NO_VALUE));
171+
const { minTaskCount, maxTaskCount, highAvailability } = props;
172+
173+
this.taskSize = new cdk.CfnParameter(this, 'TaskSize', {
174+
description: 'Fargare task size',
175+
type: 'String',
176+
default: 'medium',
177+
allowedValues: ['none', 'micro', 'small', 'medium', 'large', 'xlarge', '2xlarge', '4xlarge'],
178+
});
179+
180+
/** CFn task definition to override */
181+
const taskDef = this.service.taskDefinition.node.defaultChild as ecs.CfnTaskDefinition;
182+
183+
const cpu = scope.taskSizeMapping.findInMap(this.taskSize.valueAsString, 'cpu');
184+
const memory = scope.taskSizeMapping.findInMap(this.taskSize.valueAsString, 'memory');
185+
186+
taskDef.addPropertyOverride('Cpu', cpu);
187+
taskDef.addPropertyOverride('Memory', memory);
204188

205189
const autoScaling = this.service.autoScaleTaskCount({
206-
minCapacity: this.cfnParameters.minTaskCount.valueAsNumber,
207-
maxCapacity: this.cfnParameters.maxTaskCount.valueAsNumber,
190+
minCapacity: minTaskCount ?? 2,
191+
maxCapacity: maxTaskCount ?? 20,
208192
});
209193

210194
autoScaling.scaleOnCpuUtilization('ScaleOnCpu', {
211195
targetUtilizationPercent: 50,
212196
scaleInCooldown: cdk.Duration.seconds(60),
213197
scaleOutCooldown: cdk.Duration.seconds(60),
214198
});
199+
200+
/** CFn condition for ECS service */
201+
const serviceEnabled = new cdk.CfnCondition(this, 'ServiceEnabled', { expression: cdk.Fn.conditionNot(cdk.Fn.conditionEquals(this.taskSize, 'none')) });
202+
(this.service.node.defaultChild as ecs.CfnService).addPropertyOverride('DesiredCount', cdk.Fn.conditionIf(serviceEnabled.logicalId, cdk.Aws.NO_VALUE, 0));
203+
204+
if (typeof highAvailability != 'undefined') {
205+
/** CFn condition for auto-scaling */
206+
const autoScalingEnabled = new cdk.CfnCondition(this, 'AutoScalingEnabled', { expression: cdk.Fn.conditionAnd(serviceEnabled, highAvailability) });
207+
const target = autoScaling.node.findChild('Target') as ScalableTarget;
208+
(target.node.defaultChild as CfnScalableTarget).cfnOptions.condition = autoScalingEnabled;
209+
(target.node.findChild('ScaleOnCpu').node.defaultChild as CfnScalingPolicy).cfnOptions.condition = autoScalingEnabled;
210+
}
215211
}
216212
}

src/supabase-cdn/index.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { WebAcl } from '../aws-waf';
1616

1717
interface SupabaseCdnProps {
1818
origin: string|elb.ILoadBalancerV2;
19+
webAclArn: cdk.CfnParameter;
1920
}
2021

2122
interface BehaviorProps {
@@ -26,9 +27,6 @@ interface BehaviorProps {
2627
export class SupabaseCdn extends Construct {
2728
distribution: cf.Distribution;
2829
defaultBehaviorOptions: cf.AddBehaviorOptions;
29-
cfnParameters: {
30-
webAclArn: cdk.CfnParameter;
31-
};
3230

3331
/** Construct for CloudFront and WAF */
3432
constructor(scope: Construct, id: string, props: SupabaseCdnProps) {
@@ -39,23 +37,14 @@ export class SupabaseCdn extends Construct {
3937
? new HttpOrigin(props.origin, { protocolPolicy: cf.OriginProtocolPolicy.HTTPS_ONLY })
4038
: new LoadBalancerV2Origin(props.origin, { protocolPolicy: cf.OriginProtocolPolicy.HTTP_ONLY });
4139

42-
this.cfnParameters = {
43-
webAclArn: new cdk.CfnParameter(this, 'WebAclArn', {
44-
description: 'Web ACL for CloudFront.',
45-
type: 'String',
46-
default: '',
47-
allowedPattern: '^arn:aws:wafv2:us-east-1:[0-9]{12}:global/webacl/[\\w-]+/[\\w]{8}-[\\w]{4}-[\\w]{4}-[\\w]{4}-[\\w]{12}$|',
48-
}),
49-
};
50-
51-
const webAclUndefined = new cdk.CfnCondition(this, 'WebAclUndefined', { expression: cdk.Fn.conditionEquals(this.cfnParameters.webAclArn, '') });
40+
const defaultWebAclEnabled = new cdk.CfnCondition(this, 'DefaultWebAclEnabled', { expression: cdk.Fn.conditionEquals(props.webAclArn, '') });
5241

5342
/** Default Web ACL */
54-
const webAcl = new WebAcl(this, 'WebAcl', { description: 'Supabase Standard WebAcl' });
55-
(webAcl.node.defaultChild as cdk.CfnStack).cfnOptions.condition = webAclUndefined;
43+
const defaultWebAcl = new WebAcl(this, 'DefaultWebAcl', { description: 'Default Web ACL' });
44+
(defaultWebAcl.node.defaultChild as cdk.CfnStack).cfnOptions.condition = defaultWebAclEnabled;
5645

5746
/** Web ACL ID */
58-
const webAclId = cdk.Fn.conditionIf(webAclUndefined.logicalId, webAcl.webAclArn, this.cfnParameters.webAclArn.valueAsString);
47+
const webAclId = cdk.Fn.conditionIf(defaultWebAclEnabled.logicalId, defaultWebAcl.webAclArn, props.webAclArn.valueAsString);
5948

6049
const cachePolicy = new cf.CachePolicy(this, 'CachePolicy', {
6150
cachePolicyName: `${cdk.Aws.STACK_NAME}-CachePolicy-${cdk.Aws.REGION}`,

src/supabase-db/index.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const excludeCharacters = '%+~`#$&*()|[]{}:;<>?!\'/@\"\\=^,'; // for Password
1616

1717
interface SupabaseDatabaseProps {
1818
vpc: ec2.IVpc;
19+
highAvailability?: cdk.CfnCondition;
1920
}
2021

2122
export class SupabaseDatabase extends Construct {
@@ -31,7 +32,7 @@ export class SupabaseDatabase extends Construct {
3132
constructor(scope: Construct, id: string, props: SupabaseDatabaseProps) {
3233
super(scope, id);
3334

34-
const { vpc } = props;
35+
const { vpc, highAvailability } = props;
3536

3637
/** Database Engine */
3738
//const engine = rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_15 });
@@ -65,8 +66,12 @@ export class SupabaseDatabase extends Construct {
6566
storageEncrypted: true,
6667
});
6768

69+
const instance1 = this.cluster.node.findChild('Instance1').node.defaultChild as rds.CfnDBInstance;
70+
const instance2 = this.cluster.node.findChild('Instance2').node.defaultChild as rds.CfnDBInstance;
6871

69-
const dbInstance = this.cluster.node.findChild('Instance1') as rds.CfnDBInstance;
72+
if (typeof highAvailability !== 'undefined') {
73+
instance2.cfnOptions.condition = highAvailability;
74+
}
7075

7176
//this.instance = new rds.DatabaseInstance(this, 'Instance', {
7277
// engine,
@@ -137,7 +142,7 @@ export class SupabaseDatabase extends Construct {
137142
});
138143

139144
// Wait until the database is ready.
140-
this.migration.node.addDependency(dbInstance);
145+
this.migration.node.addDependency(instance1);
141146

142147
/** Custom resource handler to modify db user password */
143148
const userPasswordFunction = new NodejsFunction(this, 'UserPasswordFunction', {

0 commit comments

Comments
 (0)