Skip to content

Commit 2216bf8

Browse files
authored
feat:add a multi rule ALB sample with host and path based routing (#257)
* add a multi rule ALB sample with a combination of host and path based routing * Update java/alb-multi-rule-response/README.md
1 parent 5b43b74 commit 2216bf8

File tree

9 files changed

+394
-0
lines changed

9 files changed

+394
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.classpath.txt
2+
target
3+
.classpath
4+
.project
5+
.idea
6+
.settings
7+
.vscode
8+
*.iml
9+
10+
# CDK asset staging directory
11+
.cdk.staging
12+
cdk.out
13+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<!--BEGIN STABILITY BANNER-->
2+
---
3+
4+
![Stability: Stable](https://img.shields.io/badge/stability-Stable-success.svg?style=for-the-badge)
5+
6+
> **This is a stable example. It should successfully build out of the box**
7+
>
8+
> This examples does is built on Construct Libraries marked "Stable" and does not have any infrastructure prerequisites to build.
9+
10+
---
11+
<!--END STABILITY BANNER-->
12+
13+
# ALB using a combination of host and path based routing with Java AWS-CDK
14+
The ALB is backed by an EC2 instance acting as frontend client and built-in ALB response rules that simulates mobile and application api
15+
16+
## Testing the responses
17+
### testing mobile produciton api
18+
``` bash
19+
curl -H "Host: mobile.mydomain.com" [ALB-DNS-FQDN]/production
20+
```
21+
Resonse received
22+
```json
23+
{"status":"succes","apiversion":"prod_mobile_v1"}
24+
```
25+
26+
### Testing frontend production api
27+
``` bash
28+
curl -H "Host: api.mydomain.com" [ALB-DNS-FQDN]/production
29+
```
30+
31+
```json
32+
{"status":"succes","apiversion":"prod_api_v1"}
33+
```
34+
35+
## List of ALB rules
36+
![alt text](imgs/screenshot.png "screenshot of resulting rule")
37+
38+
39+
It is a Maven-based project, so you can open this directory with any Maven-compatible Java IDE, and you should be able to build and run tests from your IDE.
40+
41+
You should explore the contents of this template. It demonstrates a CDK app to create a multi-rule ALB, based on path and host headers.
42+
More information on ALB and Path routing is available here https://docs.aws.amazon.com/elasticloadbalancing/latest/application/tutorial-load-balancer-routing.html
43+
44+
The cdk.json file tells the CDK Toolkit how to execute your app. This example relies on maven to do that.
45+
46+
## Useful commands
47+
48+
* `mvn package` compile and run tests
49+
* `cdk ls` list all stacks in the app
50+
* `cdk synth` emits the synthesized CloudFormation template
51+
* `cdk deploy` deploy this stack to your default AWS account/region
52+
* `cdk diff` compare deployed stack with current state
53+
* `cdk docs` open CDK documentation
54+
55+
Enjoy!
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"app": "mvn -e -q exec:java"
3+
}
248 KB
Loading
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
3+
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>com.myorg</groupId>
7+
<artifactId>albcdkproject</artifactId>
8+
<version>0.1</version>
9+
10+
<properties>
11+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
12+
</properties>
13+
14+
<build>
15+
<plugins>
16+
<plugin>
17+
<groupId>org.apache.maven.plugins</groupId>
18+
<artifactId>maven-compiler-plugin</artifactId>
19+
<version>3.8.1</version>
20+
<configuration>
21+
<source>1.8</source>
22+
<target>1.8</target>
23+
</configuration>
24+
</plugin>
25+
26+
<plugin>
27+
<groupId>org.codehaus.mojo</groupId>
28+
<artifactId>exec-maven-plugin</artifactId>
29+
<version>1.6.0</version>
30+
<configuration>
31+
<mainClass>com.myorg.ALBProjectApp</mainClass>
32+
</configuration>
33+
</plugin>
34+
</plugins>
35+
</build>
36+
37+
<dependencies>
38+
<!-- AWS Cloud Development Kit -->
39+
<dependency>
40+
<groupId>software.amazon.awscdk</groupId>
41+
<artifactId>core</artifactId>
42+
<version>[1.26.0, 2)</version>
43+
</dependency>
44+
45+
<dependency>
46+
<groupId>software.amazon.awscdk</groupId>
47+
<artifactId>elasticloadbalancingv2</artifactId>
48+
<version>[1.26.0, 2)</version>
49+
</dependency>
50+
<dependency>
51+
<groupId>software.amazon.awscdk</groupId>
52+
<artifactId>ec2</artifactId>
53+
<version>[1.26.0, 2)</version>
54+
</dependency>
55+
<dependency>
56+
<groupId>software.amazon.awscdk</groupId>
57+
<artifactId>autoscaling</artifactId>
58+
<version>[1.26.0,2)</version>
59+
</dependency>
60+
61+
<!-- https://mvnrepository.com/artifact/junit/junit -->
62+
<dependency>
63+
<groupId>junit</groupId>
64+
<artifactId>junit</artifactId>
65+
<version>4.12</version>
66+
<scope>test</scope>
67+
</dependency>
68+
</dependencies>
69+
</project>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.myorg;
2+
3+
import software.amazon.awscdk.core.App;
4+
import software.amazon.awscdk.core.Environment;
5+
import software.amazon.awscdk.core.StackProps;
6+
7+
public class ALBProjectApp {
8+
public static void main(final String[] args) {
9+
App app = new App();
10+
11+
new ALBProjectStack(
12+
app, "ALBProjectStack", StackProps.builder().env(Environment.builder().build()).build());
13+
app.synth();
14+
}
15+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package com.myorg;
2+
3+
import com.myorg.utils.PropertyLoader;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
import software.amazon.awscdk.core.Construct;
7+
import software.amazon.awscdk.core.Stack;
8+
import software.amazon.awscdk.core.StackProps;
9+
import software.amazon.awscdk.services.autoscaling.AutoScalingGroup;
10+
import software.amazon.awscdk.services.ec2.AmazonLinuxImage;
11+
import software.amazon.awscdk.services.ec2.InstanceClass;
12+
import software.amazon.awscdk.services.ec2.InstanceSize;
13+
import software.amazon.awscdk.services.ec2.InstanceType;
14+
import software.amazon.awscdk.services.ec2.Vpc;
15+
import software.amazon.awscdk.services.elasticloadbalancingv2.ApplicationListener;
16+
import software.amazon.awscdk.services.elasticloadbalancingv2.ApplicationListenerRule;
17+
import software.amazon.awscdk.services.elasticloadbalancingv2.ApplicationLoadBalancer;
18+
import software.amazon.awscdk.services.elasticloadbalancingv2.ApplicationProtocol;
19+
import software.amazon.awscdk.services.elasticloadbalancingv2.ApplicationTargetGroup;
20+
import software.amazon.awscdk.services.elasticloadbalancingv2.ApplicationTargetGroupProps;
21+
import software.amazon.awscdk.services.elasticloadbalancingv2.ContentType;
22+
import software.amazon.awscdk.services.elasticloadbalancingv2.FixedResponse;
23+
import software.amazon.awscdk.services.elasticloadbalancingv2.IApplicationLoadBalancerTarget;
24+
import software.amazon.awscdk.services.elasticloadbalancingv2.IApplicationTargetGroup;
25+
import software.amazon.awscdk.services.elasticloadbalancingv2.TargetType;
26+
27+
public class ALBProjectStack extends Stack {
28+
29+
public ALBProjectStack(final Construct scope, final String id) {
30+
this(scope, id, null);
31+
}
32+
33+
public ALBProjectStack(final Construct scope, final String id, final StackProps props) {
34+
super(scope, id, props);
35+
36+
// property loader
37+
PropertyLoader propertyLoad = new PropertyLoader();
38+
39+
// create ALB and all anciliarry services
40+
Vpc vpc = Vpc.Builder.create(this, "VPC").build();
41+
AutoScalingGroup asg =
42+
AutoScalingGroup.Builder.create(this, "ASG")
43+
.vpc(vpc)
44+
.instanceType(InstanceType.of(InstanceClass.BURSTABLE2, InstanceSize.MICRO))
45+
.userData(propertyLoad.getUserData())
46+
.machineImage(new AmazonLinuxImage())
47+
.build();
48+
49+
ApplicationLoadBalancer lb =
50+
ApplicationLoadBalancer.Builder.create(this, "LB")
51+
.vpc(vpc)
52+
.internetFacing(Boolean.TRUE)
53+
.loadBalancerName("myalb")
54+
.build();
55+
56+
List<IApplicationLoadBalancerTarget> targets = new ArrayList<IApplicationLoadBalancerTarget>();
57+
targets.add(asg);
58+
59+
ApplicationTargetGroup webTargetGroup =
60+
new ApplicationTargetGroup(
61+
this,
62+
"MyTargetGroup",
63+
ApplicationTargetGroupProps.builder()
64+
.vpc(vpc)
65+
.targetType(TargetType.INSTANCE)
66+
.targets(targets)
67+
.port(80)
68+
.protocol(ApplicationProtocol.HTTP)
69+
.build());
70+
71+
List<IApplicationTargetGroup> targetGroups = new ArrayList<IApplicationTargetGroup>();
72+
targetGroups.add(webTargetGroup);
73+
74+
// default listener
75+
ApplicationListener http =
76+
ApplicationListener.Builder.create(this, "HTTP")
77+
.port(80)
78+
.protocol(ApplicationProtocol.HTTP)
79+
.open(true)
80+
.loadBalancer(lb)
81+
.defaultTargetGroups(targetGroups)
82+
.build();
83+
84+
// adding application listern rules
85+
ApplicationListenerRule alrProdApi =
86+
ApplicationListenerRule.Builder.create(this, "prodApi")
87+
.pathPattern("/production")
88+
.priority(1)
89+
.listener(http)
90+
.hostHeader(propertyLoad.getRestAPIHostHeader())
91+
.build();
92+
93+
ApplicationListenerRule alrProdM =
94+
ApplicationListenerRule.Builder.create(this, "prodMobile")
95+
.pathPattern("/production")
96+
.priority(2)
97+
.listener(http)
98+
.hostHeader(propertyLoad.getRestMobileHostHeader())
99+
.build();
100+
101+
ApplicationListenerRule alrSandboxApi =
102+
ApplicationListenerRule.Builder.create(this, "sandboxApi")
103+
.pathPattern("/sandbox")
104+
.priority(3)
105+
.listener(http)
106+
.hostHeader(propertyLoad.getRestAPIHostHeader())
107+
.build();
108+
109+
ApplicationListenerRule alrSandboxM =
110+
ApplicationListenerRule.Builder.create(this, "sandboxMobile")
111+
.pathPattern("/sandbox")
112+
.priority(4)
113+
.listener(http)
114+
.hostHeader(propertyLoad.getRestMobileHostHeader())
115+
.build();
116+
117+
// adding fixed responses
118+
alrProdApi.addFixedResponse(
119+
FixedResponse.builder()
120+
.statusCode("200")
121+
.contentType(ContentType.APPLICATION_JSON)
122+
.messageBody(propertyLoad.getProdApiMessageBody())
123+
.build());
124+
125+
alrProdM.addFixedResponse(
126+
FixedResponse.builder()
127+
.statusCode("200")
128+
.contentType(ContentType.APPLICATION_JSON)
129+
.messageBody(propertyLoad.getProdMobileMessageBody())
130+
.build());
131+
132+
alrSandboxApi.addFixedResponse(
133+
FixedResponse.builder()
134+
.statusCode("200")
135+
.contentType(ContentType.APPLICATION_JSON)
136+
.messageBody(propertyLoad.getSandboxApiMessageBody())
137+
.build());
138+
139+
alrSandboxM.addFixedResponse(
140+
FixedResponse.builder()
141+
.statusCode("200")
142+
.contentType(ContentType.APPLICATION_JSON)
143+
.messageBody(propertyLoad.getSandboxMobileMessageBody())
144+
.build());
145+
}
146+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.myorg.utils;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.util.Properties;
6+
import software.amazon.awscdk.services.ec2.UserData;
7+
8+
public class PropertyLoader {
9+
10+
private final UserData userData;
11+
private String prodMobileMessageBody;
12+
private String prodApiMessageBody;
13+
private String sandboxApiMessageBody;
14+
private String sandboxMobileMessageBody;
15+
private String restAPIHostHeader;
16+
private String restMobileHostHeader;
17+
18+
public PropertyLoader() {
19+
userData = UserData.forLinux();
20+
load();
21+
}
22+
23+
public UserData getUserData() {
24+
return userData;
25+
}
26+
27+
public String getProdMobileMessageBody() {
28+
return prodMobileMessageBody;
29+
}
30+
31+
public String getProdApiMessageBody() {
32+
return prodApiMessageBody;
33+
}
34+
35+
public String getSandboxApiMessageBody() {
36+
return sandboxApiMessageBody;
37+
}
38+
39+
public String getSandboxMobileMessageBody() {
40+
return sandboxMobileMessageBody;
41+
}
42+
43+
public String getRestAPIHostHeader() {
44+
return restAPIHostHeader;
45+
}
46+
47+
public String getRestMobileHostHeader() {
48+
return restMobileHostHeader;
49+
}
50+
51+
private void load() {
52+
// start loading data from the properties files
53+
try (InputStream input =
54+
PropertyLoader.class.getClassLoader().getResourceAsStream("mydata.properties")) {
55+
56+
Properties prop = new Properties();
57+
if (input == null) {
58+
System.out.println("unable to find mydata.properties");
59+
return;
60+
}
61+
62+
// get the values from the properties file
63+
prop.load(input);
64+
65+
// start populating values
66+
prodMobileMessageBody = prop.getProperty("response.prodMobileV1");
67+
prodApiMessageBody = prop.getProperty("response.prodApiV1");
68+
sandboxApiMessageBody = prop.getProperty("response.sandboxApiV1");
69+
sandboxMobileMessageBody = prop.getProperty("response.sandboxMobileV1");
70+
restAPIHostHeader = prop.getProperty("rest.api");
71+
restMobileHostHeader = prop.getProperty("rest.mobile");
72+
73+
String[] cmds = prop.getProperty("userData.commands").split("\n");
74+
if (cmds.length > 0) {
75+
for (String cmd : cmds) {
76+
userData.addCommands(cmd);
77+
}
78+
}
79+
} catch (IOException ex) {
80+
ex.printStackTrace();
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)