-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Java): add Java code for resource-overrides example. (#167)
* feat(Java): add Java code for resource-overrides example. * Add simple test. * Address PR comments
- Loading branch information
1 parent
807998a
commit f350ba2
Showing
8 changed files
with
789 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# CDK Java Example: Resource Override | ||
<!--BEGIN STABILITY BANNER--> | ||
--- | ||
|
||
![Stability: REFERENCE](https://img.shields.io/badge/stability-Reference-informational.svg?style=for-the-badge) | ||
|
||
> **This is a reference example. It may not build, and exists to demonstrate features* | ||
> | ||
> This example has code elements that will block a successful build, and should be used for reference only. | ||
--- | ||
<!--END STABILITY BANNER--> | ||
|
||
This example shows the use of the resource overrides (["escape hatch"](https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html)) mechanism. | ||
|
||
We add an `AWS::S3::Bucket` resource, and then proceed to change the properties | ||
of the underlying CloudFormation resource. | ||
|
||
There are two steps: | ||
|
||
* Access the underlying CloudFormation resource by using | ||
`construct.getNode().getDefaultChild()` or `construct.getNode().findChild(childId)`. | ||
* Change the resource by the various `add[Property]Override()` methods, | ||
or assigning to properties or `getCfnOptions()`. | ||
|
||
**NOTE** The point is to show how to change various aspects of the generated | ||
CloudFormation template. The end result is a template that cannot be successfully | ||
deployed! | ||
|
||
## Building | ||
|
||
To build this app, run `mvn compile`. This will download the required | ||
dependencies to compile the Java code. | ||
|
||
You can use your IDE to write code and unit tests, but you will need to use the | ||
CDK toolkit if you wish to synthesize/deploy stacks. | ||
|
||
## CDK Toolkit | ||
|
||
The [`cdk.json`](./cdk.json) file in the root of this repository includes | ||
instructions for the CDK toolkit on how to execute this program. | ||
|
||
Specifically, it will tell the toolkit to use the `mvn exec:java` command as the | ||
entry point of your application. After changing your Java code, you will be able | ||
to run the CDK toolkit commands as usual (Maven will recompile as needed): | ||
|
||
$ cdk ls | ||
<list all stacks in this program> | ||
|
||
$ cdk synth | ||
<outputs cloudformation template> | ||
|
||
$ cdk deploy | ||
<deploy stack to your account - trying to deploy this stack will fail, see note above> | ||
|
||
$ cdk diff | ||
<diff against deployed stack> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"app": "mvn exec:java -Dexec.mainClass=software.amazon.awscdk.examples.ResourceOverridesApp" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<?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.amazonaws.cdk</groupId> | ||
<artifactId>resource-overrides</artifactId> | ||
<version>1.0.0</version> | ||
|
||
<properties> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
</properties> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<version>3.8.1</version> | ||
<configuration> | ||
<source>1.8</source> | ||
<target>1.8</target> | ||
</configuration> | ||
</plugin> | ||
|
||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-assembly-plugin</artifactId> | ||
<version>3.1.0</version> | ||
<configuration> | ||
<descriptorRefs> | ||
<descriptorRef>jar-with-dependencies</descriptorRef> | ||
</descriptorRefs> | ||
<archive> | ||
<manifest> | ||
<mainClass>com.amazonaws.cdk.examples.ResourceOverridesApp</mainClass> | ||
</manifest> | ||
</archive> | ||
</configuration> | ||
<executions> | ||
<execution> | ||
<id>make-assembly</id> <!-- this is used for inheritance merges --> | ||
<phase>package</phase> <!-- bind to the packaging phase --> | ||
<goals> | ||
<goal>single</goal> | ||
</goals> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
|
||
</plugins> | ||
</build> | ||
|
||
<dependencies> | ||
<!-- https://mvnrepository.com/artifact/software.amazon.awscdk/core --> | ||
<dependency> | ||
<groupId>software.amazon.awscdk</groupId> | ||
<artifactId>core</artifactId> | ||
<version>1.17.1.DEVPREVIEW</version> | ||
</dependency> | ||
<!-- https://mvnrepository.com/artifact/software.amazon.awscdk/s3 --> | ||
<dependency> | ||
<groupId>software.amazon.awscdk</groupId> | ||
<artifactId>s3</artifactId> | ||
<version>1.17.1.DEVPREVIEW</version> | ||
</dependency> | ||
<!-- https://mvnrepository.com/artifact/software.amazon.awscdk/ec2 --> | ||
<dependency> | ||
<groupId>software.amazon.awscdk</groupId> | ||
<artifactId>ec2</artifactId> | ||
<version>1.17.1.DEVPREVIEW</version> | ||
</dependency> | ||
<!-- https://mvnrepository.com/artifact/software.amazon.awscdk/autoscaling --> | ||
<dependency> | ||
<groupId>software.amazon.awscdk</groupId> | ||
<artifactId>autoscaling</artifactId> | ||
<version>1.17.1.DEVPREVIEW</version> | ||
</dependency> | ||
|
||
<!-- https://mvnrepository.com/artifact/com.google.guava/guava --> | ||
<dependency> | ||
<groupId>com.google.guava</groupId> | ||
<artifactId>guava</artifactId> | ||
<version>28.1-jre</version> | ||
</dependency> | ||
|
||
<!-- https://mvnrepository.com/artifact/junit/junit --> | ||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<version>4.12</version> | ||
<scope>test</scope> | ||
</dependency> | ||
<!-- https://mvnrepository.com/artifact/org.skyscreamer/jsonassert --> | ||
<dependency> | ||
<groupId>org.skyscreamer</groupId> | ||
<artifactId>jsonassert</artifactId> | ||
<version>1.5.0</version> | ||
<scope>test</scope> | ||
</dependency> | ||
|
||
</dependencies> | ||
|
||
|
||
</project> |
13 changes: 13 additions & 0 deletions
13
...esource-overrides/src/main/java/software/amazon/awscdk/examples/ResourceOverridesApp.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package software.amazon.awscdk.examples; | ||
|
||
import software.amazon.awscdk.core.App; | ||
|
||
public class ResourceOverridesApp { | ||
public static void main(final String[] args) { | ||
App app = new App(); | ||
|
||
new ResourceOverridesStack(app, "resource-overrides"); | ||
|
||
app.synth(); | ||
} | ||
} |
164 changes: 164 additions & 0 deletions
164
...ource-overrides/src/main/java/software/amazon/awscdk/examples/ResourceOverridesStack.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
package software.amazon.awscdk.examples; | ||
|
||
import com.google.common.collect.ImmutableList; | ||
import com.google.common.collect.ImmutableMap; | ||
import software.amazon.awscdk.core.*; | ||
import software.amazon.awscdk.services.autoscaling.AutoScalingGroup; | ||
import software.amazon.awscdk.services.autoscaling.CfnLaunchConfiguration; | ||
import software.amazon.awscdk.services.ec2.*; | ||
import software.amazon.awscdk.services.s3.Bucket; | ||
import software.amazon.awscdk.services.s3.BucketEncryption; | ||
import software.amazon.awscdk.services.s3.CfnBucket; | ||
|
||
import java.util.Collections; | ||
|
||
/** | ||
* This is an example of how to override properties of underlying CloudFormation resource of | ||
* high-level CDK construct. | ||
* <p> | ||
* Note: this is just a reference code to show examples of how to use L1 resources. | ||
* Running `cdk deploy` on this app will fail, however you can still run `cdk synth` and explore | ||
* CloudFormation template that gets generated. | ||
* <p> | ||
* Note: this code shows how to access L1 resources, however you shouldn't do it unless you really need to. | ||
* As you can see below, doing some is quite cumbersome (especially in Java) and not very clean, but still possible. | ||
*/ | ||
class ResourceOverridesStack extends Stack { | ||
public ResourceOverridesStack(final Construct scope, final String name) { | ||
super(scope, name); | ||
|
||
Bucket otherBucket = Bucket.Builder.create(this, "Other").build(); | ||
|
||
Bucket bucket = Bucket.Builder.create(this, "MyBucket") | ||
.versioned(true) | ||
.encryption(BucketEncryption.KMS_MANAGED) | ||
.build(); | ||
|
||
CfnBucket bucketResource = (CfnBucket) bucket.getNode().getDefaultChild(); | ||
|
||
// | ||
// This is how to access L1 construct | ||
// | ||
accessCfnBucketExample(bucket); | ||
|
||
// | ||
// This is how to modify properties of L1 construct | ||
// | ||
modifyPropertiesExample(bucket); | ||
|
||
// | ||
// This is how to specify resource options such as dependencies, metadata, update policy | ||
// | ||
bucketResource.getNode().addDependency(otherBucket.getNode().getDefaultChild()); | ||
bucketResource.getCfnOptions().setMetadata( | ||
ImmutableMap.of("MetadataKey", "MetadataValue") | ||
); | ||
bucketResource.getCfnOptions().setUpdatePolicy( | ||
CfnUpdatePolicy.builder() | ||
.autoScalingRollingUpdate(CfnAutoScalingRollingUpdate.builder().pauseTime("390").build()) | ||
.build() | ||
); | ||
|
||
// | ||
// This is how to specify "raw" overrides at the __resource__ level | ||
// | ||
bucketResource.addOverride("Type", "AWS::S3::Bucketeer"); // even "Type" can be overridden | ||
bucketResource.addOverride("Transform", "Boom"); | ||
bucketResource.addOverride("Properties.CorsConfiguration", | ||
ImmutableMap.builder() | ||
.put("Custom", 123) | ||
.put("Bar", ImmutableList.of("A", "B")) | ||
.build() | ||
); | ||
|
||
// addPropertyOverride simply allows you to omit the "Properties." prefix | ||
bucketResource.addPropertyOverride("VersioningConfiguration.Status", "NewStatus"); | ||
bucketResource.addPropertyOverride("Token", otherBucket.getBucketArn()); | ||
// it's possible to mix L1 and L2 constructs - in this case otherBucket.getBucketName() will create "Ref:" in CloudFormation template | ||
bucketResource.addPropertyOverride("LoggingConfiguration.DestinationBucketName", otherBucket.getBucketName()); | ||
|
||
bucketResource.setAnalyticsConfigurations(Collections.singletonList(ImmutableMap.builder() | ||
.put("id", "config1") | ||
.put("storageClassAnalysis", ImmutableMap.of( | ||
"dataExport", ImmutableMap.builder() | ||
.put("outputSchemaVersion", "1") | ||
.put("destination", ImmutableMap.builder() | ||
.put("format", "html") | ||
// using L2 construct's method will work as expected | ||
.put("bucketArn", otherBucket.getBucketArn()) | ||
.build() | ||
) | ||
.build() | ||
) | ||
) | ||
.build() | ||
)); | ||
|
||
// | ||
// It is also possible to request a deletion of a value by either assigning | ||
// `null` or use the `addDeletionOverride` method | ||
// | ||
bucketResource.addDeletionOverride("Metadata"); | ||
// same as above | ||
bucketResource.addOverride("Metadata", null); | ||
bucketResource.addPropertyDeletionOverride("CorsConfiguration.Bar"); | ||
|
||
// | ||
// Example of constructs that have more L1 underlying resources and how to access them | ||
// | ||
Vpc vpc = Vpc.Builder.create(this, "VPC") | ||
.maxAzs(1) | ||
.build(); | ||
|
||
AutoScalingGroup asg = AutoScalingGroup.Builder.create(this, "ASG") | ||
.vpc(vpc) | ||
.instanceType(InstanceType.of(InstanceClass.MEMORY4, InstanceSize.XLARGE)) | ||
.machineImage(new AmazonLinuxImage()) | ||
.build(); | ||
|
||
// | ||
// The default child resource is called `Resource`, but secondary resources, such as | ||
// an LaunchConfig, InstanceRole will have a different ID. | ||
// See https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.ConstructNode.html#defaultchild | ||
// You can see all the resources under given construct by running `cdk synth` and looking for `aws:cdk:path` | ||
// | ||
CfnLaunchConfiguration launchConfiguration = (CfnLaunchConfiguration) asg.getNode().findChild("LaunchConfig"); | ||
launchConfiguration.addPropertyOverride("Foo.Bar", "Hello"); | ||
} | ||
|
||
/** | ||
* Example of accessing L1 bucket resource from L2 bucket construct. | ||
* <p> | ||
* You can read more on L1 vs L2 constructs here: https://aws.amazon.com/blogs/developer/contributing-to-the-aws-cloud-development-kit/ | ||
*/ | ||
private void accessCfnBucketExample(Bucket bucket) { | ||
// accessing through finding a child of specific type (not pretty in Java) | ||
CfnBucket bucketResource1 = (CfnBucket) bucket.getNode().getChildren() | ||
.stream() | ||
.filter(child -> ((CfnResource) child).getCfnResourceType().equals("AWS::S3::Bucket")) | ||
.findFirst() | ||
.get(); | ||
|
||
// accessing through getting a default child | ||
CfnBucket bucketResource2 = (CfnBucket) bucket.getNode().getDefaultChild(); | ||
|
||
assert bucketResource1.equals(bucketResource2); | ||
} | ||
|
||
/** | ||
* Example of how properties of CloudFormation resource can be modified. | ||
* Paths for the properties can be found in CloudFormation documentation. | ||
* For S3 bucket properties see: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html | ||
*/ | ||
private void modifyPropertiesExample(Bucket bucket) { | ||
CfnBucket bucketCfnResource = (CfnBucket) bucket.getNode().getDefaultChild(); | ||
|
||
// This is an invalid CF property, but there is no validation at this point, so anything can be set. | ||
// This is just to show that anything can be set at this point, but it's only validated ones the stack | ||
// is being deployed to CloudFormation. | ||
bucketCfnResource.addPropertyOverride("BucketEncryption.ServerSideEncryptionConfiguration.0.EncryptEverythingAndAlways", true); | ||
|
||
// This is a valid CF property | ||
bucketCfnResource.addPropertyDeletionOverride("BucketEncryption.ServerSideEncryptionConfiguration.0.ServerSideEncryptionByDefault"); | ||
} | ||
} |
Oops, something went wrong.