Fix ALB listener default action, auto-import numberOfAzs, and correct docs

- Fix HTTP listener in spicy-alb.ts missing default action when no certificate
  is provided, which would cause CDK synth to fail
- Auto-import numberOfAzs from VPC stack exports (NumberOfAZs) in cluster,
  service, and ALB stacks when not provided via context
- Fix CDK_SYNTH_EXAMPLES.md ALB examples using raw vpcId/subnetIds that don't
  match the actual fromContext() implementation (requires clusterName)
- Fix docs overstating "only clusterName required" to list actual required params
- Remove package-lock.json and add to .gitignore (project uses pnpm)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 16:15:40 -08:00
parent 68684df471
commit fa1e865f50
7 changed files with 80 additions and 47 deletions

View File

@@ -161,12 +161,6 @@ export class SpicyAlb extends Construct {
this.loadBalancer.logAccessLogs(props.logsBucket, prefix);
}
// HTTP Listener
this.httpListener = this.loadBalancer.addListener('HTTPListener', {
port: 80,
protocol: elbv2.ApplicationProtocol.HTTP,
});
// HTTPS Listener (if certificate provided)
if (props.certificateArn) {
this.httpsListener = this.loadBalancer.addListener('HTTPSListener', {
@@ -178,17 +172,28 @@ export class SpicyAlb extends Construct {
messageBody: 'No target groups configured',
}),
});
}
// HTTP→HTTPS redirect (if enabled, default true)
if (props.redirectHttpToHttps !== false) {
this.httpListener.addAction('RedirectToHTTPS', {
action: elbv2.ListenerAction.redirect({
protocol: 'HTTPS',
port: '443',
permanent: true,
}),
});
}
// HTTP Listener - redirect to HTTPS if certificate provided, otherwise serve as primary
if (props.certificateArn && props.redirectHttpToHttps !== false) {
this.httpListener = this.loadBalancer.addListener('HTTPListener', {
port: 80,
protocol: elbv2.ApplicationProtocol.HTTP,
defaultAction: elbv2.ListenerAction.redirect({
protocol: 'HTTPS',
port: '443',
permanent: true,
}),
});
} else {
this.httpListener = this.loadBalancer.addListener('HTTPListener', {
port: 80,
protocol: elbv2.ApplicationProtocol.HTTP,
defaultAction: elbv2.ListenerAction.fixedResponse(404, {
contentType: 'text/plain',
messageBody: 'No target groups configured',
}),
});
}
// Blue/Green DNS configuration

View File

@@ -129,10 +129,18 @@ export class SpicyAlbStack extends cdk.Stack {
// Import all VPC details from VPC stack exports
const vpcCidrBlock = cdk.Fn.importValue(`${vpcStackName}-VPCCIDR`).toString();
// numberOfAzs: use context value if provided, otherwise auto-import from VPC stack export
const numberOfAzsRaw = app.node.tryGetContext('numberOfAzs');
const numberOfAzs = numberOfAzsRaw ? parseInt(numberOfAzsRaw, 10) : NaN;
let numberOfAzs: number;
if (numberOfAzsRaw) {
numberOfAzs = parseInt(numberOfAzsRaw, 10);
} else {
const imported = cdk.Fn.importValue(`${vpcStackName}-NumberOfAZs`).toString();
numberOfAzs = parseInt(imported, 10);
}
if (!numberOfAzs || Number.isNaN(numberOfAzs)) {
throw new Error('numberOfAzs is required in context (2-4) to import VPC subnets for ALB.');
throw new Error('numberOfAzs is required (2-4). Provide via context or ensure VPC stack exports NumberOfAZs.');
}
const azs = ['A', 'B', 'C', 'D'].slice(0, Math.min(Math.max(numberOfAzs, 1), 4));

View File

@@ -243,10 +243,18 @@ export class SpicyEcsClusterStack extends cdk.Stack {
'vpcStackName is required. Provide vpcStackName to import all VPC details from VPC stack exports.'
);
}
// numberOfAzs: use context value if provided, otherwise auto-import from VPC stack export
const numberOfAzsRaw = app.node.tryGetContext('numberOfAzs');
const numberOfAzs = numberOfAzsRaw ? parseInt(numberOfAzsRaw, 10) : NaN;
let numberOfAzs: number;
if (numberOfAzsRaw) {
numberOfAzs = parseInt(numberOfAzsRaw, 10);
} else {
// Auto-import from VPC stack export
const imported = cdk.Fn.importValue(`${vpcStackName}-NumberOfAZs`).toString();
numberOfAzs = parseInt(imported, 10);
}
if (!numberOfAzs || Number.isNaN(numberOfAzs)) {
throw new Error('numberOfAzs is required in context (2-4) to import subnets from the VPC stack.');
throw new Error('numberOfAzs is required (2-4). Provide via context or ensure VPC stack exports NumberOfAZs.');
}
// Tags

View File

@@ -187,10 +187,18 @@ export class SpicyEcsServiceStack extends cdk.Stack {
// Import all VPC details from VPC stack exports
const vpcCidrBlock = cdk.Fn.importValue(`${vpcStackName}-VPCCIDR`).toString();
// numberOfAzs: use context value if provided, otherwise auto-import from VPC stack export
const numberOfAzsRaw = app.node.tryGetContext('numberOfAzs');
const numberOfAzs = numberOfAzsRaw ? parseInt(numberOfAzsRaw, 10) : NaN;
let numberOfAzs: number;
if (numberOfAzsRaw) {
numberOfAzs = parseInt(numberOfAzsRaw, 10);
} else {
const imported = cdk.Fn.importValue(`${vpcStackName}-NumberOfAZs`).toString();
numberOfAzs = parseInt(imported, 10);
}
if (!numberOfAzs || Number.isNaN(numberOfAzs)) {
throw new Error('numberOfAzs is required in context (2-4) to import VPC subnets.');
throw new Error('numberOfAzs is required (2-4). Provide via context or ensure VPC stack exports NumberOfAZs.');
}
const azs = ['A', 'B', 'C', 'D'].slice(0, Math.min(Math.max(numberOfAzs, 1), 4));