Skip to content

Commit

Permalink
Add examples code
Browse files Browse the repository at this point in the history
  • Loading branch information
neovasili committed Sep 3, 2023
1 parent 35e3ff4 commit 4832fa2
Show file tree
Hide file tree
Showing 23 changed files with 695 additions and 29 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ According to the blast radius:

## Dependency problematic situations

Creation is not an issue in most of the cases, we just provide the desired values from one stack to another and "the magic" happens. Problems appear when we have to change something in that dependencies, either if we want to remove a no longer used dependency or if we want to change the value of the "shared" value between stacks.

### Remove an unused exported value

**Affects**:
Expand All @@ -44,4 +46,4 @@ E.g. security group from `stackA` that is used in `stackB`.

CDK will naturally follow the stacks dependency tree order to apply changes but exported value in stackA cannot be updated since it’s used in `stackB` and can happen that CloudFormation is unable to know if stackB needs to update/remove/delete the usage of that value.

In this case we can even run into a situation where we cannot update stackB independently without removing any reference to the old value first, which can be problematic or even unnacceptable.
In this case we can even run into a situation where we cannot update stackB independently without removing any reference to the old value first, which can be problematic or even unacceptable.
142 changes: 134 additions & 8 deletions bin/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,146 @@
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { Tagger } from '../lib/aspects';
import { StackA, StackB } from '../lib/stacks';

const app = new cdk.App();

const stackA = new StackA(app, 'StackA', {
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});
/**
* 01 - Basic Example
*
* Simple non-deterministic inherit dependency between a stackA defining VPC and
* stackB creating a security group within that VPC
*
import { ExampleA, ExampleB } from '../lib/stacks';
const stackA = new ExampleA(app, 'ExampleA');
const stackB = new StackB(app, 'StackB', {
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
const stackB = new ExampleB(app, 'ExampleB', {
vpc: stackA.vpc,
securityGroup: stackA.securityGroup,
securityGroupSSM: stackA.securityGroupSSM,
managementSecurityGroup: stackA.managementSecurityGroup,
});
*/

/**
* 02 - DB Example
*
* Simple non-deterministic inherit dependency between a stackA defining a Database and
* stackB passing its endpoint to an ECS service
*
import { StackA, StackB } from '../lib/stacks';
const env = { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION };
const stackA = new StackA(app, 'ExampleA', { env });
const stackB = new StackB(app, 'ExampleB', {
env,
db: stackA.db,
});
*/

/**
* 03 - CloudFront example
*
* Simple deterministic reflective dependency of CloudFront distribution that uses bucket in other stack
*
import { SharedStack, AppStack } from '../lib/stacks';
const stackA = new SharedStack(app, 'ExampleA');
const stackB = new AppStack(app, 'ExampleB', {
distribution: stackA.distribution,
});
*/

/**
* 04 - ALB example
*
* Deterministic reflective dependency of ALB that have as target a ECS service defined in other stack
*
import { AlbStack, ServiceStack } from '../lib/stacks';
const env = { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION };
const stackA = new AlbStack(app, 'ExampleA', { env });
const stackB = new ServiceStack(app, 'ExampleB', {
env,
ecsCluster: stackA.ecsCluster,
albListener: stackA.albListener,
});
*/

/**
* 05 - Manual export
*
* Explicit export and import of values across two stacks
*
import { ExportingStack, ImportingStack } from '../lib/stacks';
const stackA = new ExportingStack(app, 'ExampleA');
const stackB = new ImportingStack(app, 'ExampleB', {
vpcId: stackA.vpcId,
});
stackB.addDependency(stackA);
*/

/**
* 06 - Static values
*
* Share static values across stacks through code
*
import { CommonStack, NewServiceStack } from '../lib/stacks';
const env = {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
};
const stackA = new CommonStack(app, 'ExampleA', { env });
const stackB = new NewServiceStack(app, 'ExampleB', { env });
stackB.addDependency(stackA);
*/

/**
* 07 - SSM parameters
*
* Share values across stacks using SSM parameters
*
import { NetworkStack, ApplicationStack } from '../lib/stacks';
const env = {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
};
const stackA = new NetworkStack(app, 'ExampleA', { env });
const stackB = new ApplicationStack(app, 'ExampleB', { env });
stackB.addDependency(stackA);
*/

/**
* 08 - SSM parameters
*
* Share values across stacks using SSM parameters
*
*/
import { CoreStack, DemoStack } from '../lib/stacks';

const env = {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
};

const stackA = new CoreStack(app, 'ExampleA', { env });

const stackB = new DemoStack(app, 'ExampleB', { env });

stackB.addDependency(stackA);

cdk.Aspects.of(stackA).add(new Tagger({
project: 'cdkday-talk',
Expand Down
7 changes: 0 additions & 7 deletions cdk.context.json

This file was deleted.

2 changes: 1 addition & 1 deletion lib/aspects/tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ interface TaggerProps {
}

/**
* CDK Aspect to apply some Nira default tags to all resources in the scope provided
* CDK Aspect to apply some default tags to all resources in the scope provided
*
* @example
* import { Aspects } from 'aws-cdk-lib';
Expand Down
23 changes: 23 additions & 0 deletions lib/stacks/01-basic-example/stack-a.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';

export class ExampleA extends cdk.Stack {
public readonly vpc: ec2.IVpc;
public readonly managementSecurityGroup: ec2.ISecurityGroup;

constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

this.vpc = new ec2.Vpc(this, 'MyVpc', {
vpcName: 'cdk-day-vpc',
maxAzs: 3,
natGateways: 1,
restrictDefaultSecurityGroup: false,
});

this.managementSecurityGroup = new ec2.SecurityGroup(this, 'ManagementSecurityGroup', {
vpc: this.vpc,
});
}
}
20 changes: 20 additions & 0 deletions lib/stacks/01-basic-example/stack-b.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';

interface ExampleBProps extends cdk.StackProps {
vpc: ec2.IVpc;
managementSecurityGroup: ec2.ISecurityGroup;
}

export class ExampleB extends cdk.Stack {

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

const mySecurityGroup = new ec2.SecurityGroup(this, 'MySecurityGroup', {
vpc: props.vpc,
});
mySecurityGroup.addIngressRule(props.managementSecurityGroup, ec2.Port.allTraffic());
}
}
22 changes: 22 additions & 0 deletions lib/stacks/02-db-example/stack-a.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as rds from 'aws-cdk-lib/aws-rds';
import { Construct } from 'constructs';

export class StackA extends cdk.Stack {
public readonly db: rds.IDatabaseInstance;

constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

const vpc = new ec2.Vpc(this, 'MyVpc', {
vpcName: 'cdk-day-vpc',
});

this.db = new rds.DatabaseInstance(this, 'MyDb', {
engine: rds.DatabaseInstanceEngine.POSTGRES,
vpc,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
}
}
41 changes: 41 additions & 0 deletions lib/stacks/02-db-example/stack-b.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecr from 'aws-cdk-lib/aws-ecr';
import { Construct } from 'constructs';

interface StackBProps extends cdk.StackProps {
db: rds.IDatabaseInstance;
}

export class StackB extends cdk.Stack {

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

const cluster = new ecs.Cluster(this, 'MyEcsCluster', {
vpc: ec2.Vpc.fromLookup(this, 'MyVpc', {
vpcName: 'cdk-day-vpc',
}),
});

const taskDefinition = new ecs.FargateTaskDefinition(this, 'MyTask');

taskDefinition.addContainer('MyApp', {
image: ecs.RepositoryImage.fromEcrRepository(
ecr.Repository.fromRepositoryName(this, 'MyAppEcrRepo', 'my-app'),
'latest',
),
environment: {
DB_ENDPOINT: props.db.dbInstanceEndpointAddress,
},
});

new ecs.FargateService(this, 'MyEcsService', {
cluster,
taskDefinition,
desiredCount: 0,
});
}
}
21 changes: 21 additions & 0 deletions lib/stacks/03-cloudfront-example/stack-a.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
import { Construct } from 'constructs';

export class SharedStack extends cdk.Stack {
public readonly distribution: cloudfront.IDistribution;

constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

this.distribution = new cloudfront.Distribution(this, 'MyDistribution', {
defaultBehavior: {
origin: new origins.S3Origin(
new s3.Bucket(this, 'MyDefaultBucket'),
),
},
});
}
}
21 changes: 21 additions & 0 deletions lib/stacks/03-cloudfront-example/stack-b.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
import { Construct } from 'constructs';

interface AppStackProps extends cdk.StackProps {
distribution: cloudfront.IDistribution;
}

export class AppStack extends cdk.Stack {

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

const appBucket = new s3.Bucket(this, 'MyAppBucket');

const distribution = props.distribution as cloudfront.Distribution;
distribution.addBehavior('/my-app/', new origins.S3Origin(appBucket));
}
}
33 changes: 33 additions & 0 deletions lib/stacks/04-alb-example/stack-a.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as cdk from 'aws-cdk-lib';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as alb from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { Construct } from 'constructs';

export class AlbStack extends cdk.Stack {
public readonly ecsCluster: ecs.ICluster;
public readonly albListener: alb.IApplicationListener;

constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

const vpc = ec2.Vpc.fromLookup(this, 'MyVpc', {
vpcName: 'cdk-day-vpc',
});

this.ecsCluster = new ecs.Cluster(this, 'MyEcsCluster', {
vpc,
});

const loadBalancer = new alb.ApplicationLoadBalancer(this, 'MyAlb', {
vpc,
});

this.albListener = loadBalancer.addListener('default', {
port: 80,
defaultAction: alb.ListenerAction.fixedResponse(400, {
messageBody: 'You must use a service path',
}),
});
}
}
Loading

0 comments on commit 4832fa2

Please sign in to comment.