Initial commit: Spicy CDK automation framework
Jenkins shared library and CDK constructs for AWS infrastructure. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
164
resources/lib/stacks/spicy-vpc-stack.ts
Normal file
164
resources/lib/stacks/spicy-vpc-stack.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
import * as cdk from 'aws-cdk-lib/core';
|
||||
import { Construct } from 'constructs';
|
||||
import { SpicyVpc, SpicyVpcProps, SubnetCidrConfig } from '../constructs/spicy-vpc';
|
||||
|
||||
/**
|
||||
* Props for SpicyVpcStack
|
||||
* Extends SpicyVpcProps but makes tags optional since we can derive from context
|
||||
*/
|
||||
export interface SpicyVpcStackProps extends cdk.StackProps {
|
||||
/**
|
||||
* VPC configuration - all SpicyVpcProps except tags (derived from stack props)
|
||||
*/
|
||||
readonly vpcConfig?: Omit<SpicyVpcProps, 'tags'>;
|
||||
|
||||
/**
|
||||
* Owner tag
|
||||
*/
|
||||
readonly ownerTag: string;
|
||||
|
||||
/**
|
||||
* Product tag
|
||||
*/
|
||||
readonly productTag: string;
|
||||
|
||||
/**
|
||||
* Component tag
|
||||
*/
|
||||
readonly componentTag: string;
|
||||
|
||||
/**
|
||||
* Build identifier (e.g., git SHA)
|
||||
*/
|
||||
readonly buildTag?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* SpicyVpcStack - A CloudFormation stack that creates a Spicy VPC
|
||||
*
|
||||
* This stack can be deployed via CDK CLI or from Jenkins pipelines.
|
||||
* Configuration can be provided via:
|
||||
* 1. Direct props
|
||||
* 2. CDK context (cdk deploy -c key=value)
|
||||
* 3. Environment variables
|
||||
*/
|
||||
export class SpicyVpcStack extends cdk.Stack {
|
||||
/** The VPC construct */
|
||||
public readonly spicyVpc: SpicyVpc;
|
||||
|
||||
constructor(scope: Construct, id: string, props: SpicyVpcStackProps) {
|
||||
super(scope, id, props);
|
||||
|
||||
// Create the VPC
|
||||
this.spicyVpc = new SpicyVpc(this, 'SpicyVpc', {
|
||||
...props.vpcConfig,
|
||||
tags: {
|
||||
owner: props.ownerTag,
|
||||
product: props.productTag,
|
||||
component: props.componentTag,
|
||||
build: props.buildTag,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SpicyVpcStack from CDK context values
|
||||
* This is useful when deploying from Jenkins where context is passed via -c flags
|
||||
*/
|
||||
static fromContext(scope: Construct, id: string, stackProps?: cdk.StackProps): SpicyVpcStack {
|
||||
const app = scope.node.root as cdk.App;
|
||||
|
||||
// Required context values
|
||||
const ownerTag = app.node.tryGetContext('ownerTag') ?? 'SpicyTeam';
|
||||
const productTag = app.node.tryGetContext('productTag') ?? 'spicy';
|
||||
const componentTag = app.node.tryGetContext('componentTag') ?? 'spicy-VPC';
|
||||
const buildTag = app.node.tryGetContext('build');
|
||||
|
||||
// Optional VPC configuration from context
|
||||
const vpcCidr = app.node.tryGetContext('vpcCidr') as string | undefined;
|
||||
const vpcTenancy = app.node.tryGetContext('vpcTenancy') as 'default' | 'dedicated' | undefined;
|
||||
const numberOfAzs = app.node.tryGetContext('numberOfAzs') as string | undefined;
|
||||
const availabilityZones = app.node.tryGetContext('availabilityZones') as string | undefined;
|
||||
const createPrivateSubnets = app.node.tryGetContext('createPrivateSubnets') as string | undefined;
|
||||
const createAdditionalPrivateSubnets = app.node.tryGetContext('createAdditionalPrivateSubnets') as
|
||||
| string
|
||||
| undefined;
|
||||
const publicSubnetTag = app.node.tryGetContext('publicSubnetTag') as string | undefined;
|
||||
const privateSubnetATag = app.node.tryGetContext('privateSubnetATag') as string | undefined;
|
||||
const privateSubnetBTag = app.node.tryGetContext('privateSubnetBTag') as string | undefined;
|
||||
|
||||
// Parse subnet CIDRs from context
|
||||
const subnetCidrs = SpicyVpcStack.parseSubnetCidrsFromContext(app);
|
||||
|
||||
// Build VPC config using a mutable object then cast
|
||||
const vpcConfigBuilder: {
|
||||
vpcCidr?: string;
|
||||
vpcTenancy?: 'default' | 'dedicated';
|
||||
numberOfAzs?: 2 | 3 | 4;
|
||||
availabilityZones?: string[];
|
||||
createPrivateSubnets?: boolean;
|
||||
createAdditionalPrivateSubnets?: boolean;
|
||||
publicSubnetTag?: string;
|
||||
privateSubnetATag?: string;
|
||||
privateSubnetBTag?: string;
|
||||
subnetCidrs?: SpicyVpcProps['subnetCidrs'];
|
||||
} = {};
|
||||
|
||||
if (vpcCidr) vpcConfigBuilder.vpcCidr = vpcCidr;
|
||||
if (vpcTenancy) vpcConfigBuilder.vpcTenancy = vpcTenancy;
|
||||
if (numberOfAzs) vpcConfigBuilder.numberOfAzs = parseInt(numberOfAzs, 10) as 2 | 3 | 4;
|
||||
if (availabilityZones) {
|
||||
vpcConfigBuilder.availabilityZones = availabilityZones.split(',');
|
||||
}
|
||||
if (createPrivateSubnets !== undefined) {
|
||||
vpcConfigBuilder.createPrivateSubnets = createPrivateSubnets === 'true';
|
||||
}
|
||||
if (createAdditionalPrivateSubnets !== undefined) {
|
||||
vpcConfigBuilder.createAdditionalPrivateSubnets = createAdditionalPrivateSubnets === 'true';
|
||||
}
|
||||
if (publicSubnetTag) vpcConfigBuilder.publicSubnetTag = publicSubnetTag;
|
||||
if (privateSubnetATag) vpcConfigBuilder.privateSubnetATag = privateSubnetATag;
|
||||
if (privateSubnetBTag) vpcConfigBuilder.privateSubnetBTag = privateSubnetBTag;
|
||||
if (subnetCidrs && Object.keys(subnetCidrs).length > 0) {
|
||||
vpcConfigBuilder.subnetCidrs = subnetCidrs;
|
||||
}
|
||||
|
||||
return new SpicyVpcStack(scope, id, {
|
||||
...stackProps,
|
||||
ownerTag,
|
||||
productTag,
|
||||
componentTag,
|
||||
buildTag,
|
||||
vpcConfig: vpcConfigBuilder,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse subnet CIDR configurations from CDK context
|
||||
*/
|
||||
private static parseSubnetCidrsFromContext(app: cdk.App): SpicyVpcProps['subnetCidrs'] {
|
||||
const cidrs: SpicyVpcProps['subnetCidrs'] = {};
|
||||
|
||||
const azLetters = ['a', 'b', 'c', 'd'] as const;
|
||||
|
||||
for (const az of azLetters) {
|
||||
const azUpper = az.toUpperCase();
|
||||
const publicCidr = app.node.tryGetContext(`publicSubnet${azUpper}Cidr`);
|
||||
const private1Cidr = app.node.tryGetContext(`privateSubnet${azUpper}1Cidr`);
|
||||
const private2Cidr = app.node.tryGetContext(`privateSubnet${azUpper}2Cidr`);
|
||||
|
||||
if (publicCidr || private1Cidr || private2Cidr) {
|
||||
const config: SubnetCidrConfig = {
|
||||
publicCidr: publicCidr ?? '',
|
||||
private1Cidr: private1Cidr ?? '',
|
||||
};
|
||||
if (private2Cidr) {
|
||||
config.private2Cidr = private2Cidr;
|
||||
}
|
||||
cidrs[az] = config;
|
||||
}
|
||||
}
|
||||
|
||||
return cidrs;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user