Skip to content

Commit

Permalink
Merge branch 'main' into feature/aws-samples#1027
Browse files Browse the repository at this point in the history
  • Loading branch information
kaiz-io authored Aug 3, 2024
2 parents 97c114a + 4d19f89 commit eb14cc4
Show file tree
Hide file tree
Showing 27 changed files with 820 additions and 4,312 deletions.
13 changes: 13 additions & 0 deletions java/custom-logical-names/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.classpath.txt
target
.classpath
.project
.idea
.settings
.vscode
*.iml

# CDK asset staging directory
.cdk.staging
cdk.out

92 changes: 92 additions & 0 deletions java/custom-logical-names/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Custom Logical Names

<!--BEGIN STABILITY BANNER-->

---

![Stability: Stable](https://img.shields.io/badge/stability-Stable-success.svg?style=for-the-badge)

> **This is a stable example. It should successfully build out of the box**
>
> This example is built on Construct Libraries marked "Stable" and does not have any infrastructure prerequisites to build.
---
<!--END STABILITY BANNER-->

This sample shows how you can override the behavior for allocating logical names to CloudFormation resources in the CDK.

It implements a feature that allows users to specify a prefix for all logical names using the `prefix` context key.

## Usage

1. Extend your stacks from [`BaseStack`](src/main/java/com/myorg/BaseStack.java) instead of `Stack`.
2. Specify the context when calling the CLI through `--context prefix=PREFIX`.

## Implementation

The [`BaseStack`](src/main/java/com/myorg/BaseStack.java) class implements this custom behavior. Using a base stack is a
common and recommended pattern for reusing policy within an organization.

Then, any stack that derives from [`BaseStack`](src/main/java/com/myorg/BaseStack.java) will automatically have this
behavior.

## Build

To build this example, you need to be in this example's root directory. Then run the following:

```bash
npm install -g aws-cdk
npm install
cdk synth
```

This will install the necessary CDK, then this example's dependencies, and then build the CloudFormation template. The resulting CloudFormation template will be in the `cdk.out` directory.

## Deploy

Run `cdk deploy --context prefix=PREFIX`. This will deploy / redeploy your Stack to your AWS Account.

## Example

Without prefix:

```shell
$ cdk synth -j
{
"Resources": {
"MyTopic86869434": {
"Type": "AWS::SNS::Topic"
},
"MyBucketF68F3FF0": {
"Type": "AWS::S3::Bucket"
}
}
}
```

With prefix:

```shell
$ cdk synth -j -c prefix="MyTeam"
{
"Resources": {
"MyTeamMyTopic86869434": {
"Type": "AWS::SNS::Topic"
},
"MyTeamMyBucketF68F3FF0": {
"Type": "AWS::S3::Bucket"
}
}
}
```

## Useful commands

```
* `mvn clean package` compile and run tests
* `cdk ls` list all stacks in the app
* `cdk synth` emits the synthesized CloudFormation template
* `cdk deploy` deploy this stack to your default AWS account/region
* `cdk diff` compare deployed stack with current state
* `cdk docs` open CDK documentation
```
67 changes: 67 additions & 0 deletions java/custom-logical-names/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"app": "mvn -e -q compile exec:java",
"watch": {
"include": [
"**"
],
"exclude": [
"README.md",
"cdk*.json",
"target",
"pom.xml",
"src/test"
]
},
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
"aws",
"aws-cn"
],
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
"@aws-cdk/aws-iam:minimizePolicies": true,
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
"@aws-cdk/core:enablePartitionLiterals": true,
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
"@aws-cdk/aws-route53-patters:useCertificate": true,
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
"@aws-cdk/aws-redshift:columnId": true,
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
"@aws-cdk/aws-kms:aliasNameRef": true,
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true
}
}
58 changes: 58 additions & 0 deletions java/custom-logical-names/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>

<groupId>com.myorg</groupId>
<artifactId>custom-logical-names</artifactId>
<version>0.1</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cdk.version>2.143.0</cdk.version>
<constructs.version>[10.0.0,11.0.0)</constructs.version>
<junit.version>5.7.1</junit.version>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<release>17</release>
</configuration>
</plugin>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<mainClass>com.myorg.CustomLogicalNamesApp</mainClass>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>software.amazon.awscdk</groupId>
<artifactId>aws-cdk-lib</artifactId>
<version>${cdk.version}</version>
</dependency>
<dependency>
<groupId>software.constructs</groupId>
<artifactId>constructs</artifactId>
<version>${constructs.version}</version>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
37 changes: 37 additions & 0 deletions java/custom-logical-names/src/main/java/com/myorg/BaseStack.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.myorg;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import software.amazon.awscdk.CfnElement;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.constructs.Construct;

import java.util.Optional;

public class BaseStack extends Stack {

public BaseStack(@Nullable Construct scope, @Nullable String id, @Nullable StackProps props) {
super(scope, id, props);
}

@Override
protected @NotNull String allocateLogicalId(@NotNull CfnElement element) {
String originalLogicalId = super.allocateLogicalId(element);
return Optional.of(this)
.map(Stack::getNode)
.flatMap(
node -> Optional.of("prefix")
.map(node::tryGetContext)
.filter(String.class::isInstance)
.map(String.class::cast)
.map(StringBuilder::new)
)
.flatMap(
stringBuilder -> Optional.of(originalLogicalId)
.map(stringBuilder::append)
.map(StringBuilder::toString)
)
.orElse(originalLogicalId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.myorg;

import software.amazon.awscdk.App;
import software.amazon.awscdk.StackProps;

public class CustomLogicalNamesApp {
public static void main(final String[] args) {
App app = new App();
StackProps stackProps = StackProps.builder().build();
new CustomLogicalNamesStack(app, "CustomLogicalNamesStack", stackProps);
app.synth();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.myorg;

import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.s3.Bucket;
import software.amazon.awscdk.services.sns.Topic;
import software.constructs.Construct;

public class CustomLogicalNamesStack extends BaseStack {
public CustomLogicalNamesStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
new Topic(this, "MyTopic");
new Bucket(this, "MyBucket");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.myorg;

import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import software.amazon.awscdk.App;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.assertions.Template;

import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import static software.amazon.awscdk.App.Builder;

public class CustomLogicalNamesTest {

@Test
public void testStack() {
String prefixKey = "prefix";
String prefixValue = "YourTeam";
App app = Builder.create()
.context(Map.of(prefixKey, prefixValue))
.build();
StackProps stackProps = StackProps.builder().build();
CustomLogicalNamesStack customLogicalNamesStack = new CustomLogicalNamesStack(app, "test", stackProps);
Set<String> resourcesNames = extractResourcesNamesFormStack(customLogicalNamesStack);
// check if the prefix supplied on the context is used for all the resources in the stack
Assertions.assertTrue(resourcesNames.stream().allMatch(name -> name != null && name.startsWith(prefixValue)));
}

private @NotNull Set<String> extractResourcesNamesFormStack(Stack stack) {
var rawNamesSet = Optional.of(stack)
.map(Template::fromStack)
.map(Template::toJSON)
.map(json -> json.get("Resources"))
.filter(Map.class::isInstance)
.map(Map.class::cast)
.map(Map::keySet)
.orElseGet(Set::of);
Set<String> resourcesNames = new HashSet<>();
for (Object resource : rawNamesSet) {
Optional.of(resource)
.filter(String.class::isInstance)
.map(String.class::cast)
.ifPresent(resourcesNames::add);
}
return resourcesNames;
}
}
32 changes: 32 additions & 0 deletions python/route53-failover/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# CDK Failover DNS with Route 53 Health Check

This sample project demonstrates how to create a Failover DNS record in Route 53 using a CDK application. It leverages the Route 53 Health Check feature to monitor the status of endpoints and automatically fail over to a backup endpoint in case of failure. Additionally, it configures SNS notifications to alert administrators when a failover event occurs, ensuring prompt awareness and response.

## Architecture

The architecture of this solution is illustrated in the following diagram:

![Architecture Diagram](images/architecture.png)

The key components of the architecture are:

1. **Primary Endpoint**: The main endpoint that serves traffic under normal circumstances.
2. **Secondary Endpoint**: The backup endpoint that takes over traffic when the primary endpoint fails.
3. **Route 53 Hosted Zone**: The DNS hosted zone where the Failover DNS record is created.
4. **Route 53 Health Checks**: Health checks that monitor the availability of the primary and secondary endpoints.
5. **Route 53 Failover DNS Record**: The DNS record that routes traffic to the primary endpoint by default, but automatically switches to the secondary endpoint when the primary endpoint fails the health check.
6. **SNS Topic**: The Simple Notification Service (SNS) topic that publishes notifications when a failover event occurs.
7. **SNS Subscription**: The subscription to the SNS topic, which can be configured to deliver notifications via email or other channels.

## Getting Started

To get started with this project, follow these steps:

1. Clone the repository.
2. Install the required dependencies using `npm install`.
3. Configure the necessary AWS credentials and environment variables.
4. Select a Route 53 HostedZone that can be used for this project.
5. **Provide the required context values in the `cdk.json` file, including `domain` refering the HostedZone, `email` to get notifications, `primaryRegion`, and `secondaryRegion` to deploy the sample application.**
6. Deploy the CDK application using `cdk deploy`.

Refer to the project's documentation for more detailed instructions and configuration options.
Loading

0 comments on commit eb14cc4

Please sign in to comment.