Skip to content

Commit

Permalink
feat:add a multi rule ALB sample with host and path based routing (#257)
Browse files Browse the repository at this point in the history
* add a multi rule ALB sample with a combination of host and path based routing
* Update java/alb-multi-rule-response/README.md
  • Loading branch information
nataibi authored Mar 17, 2020
1 parent 5b43b74 commit 2216bf8
Show file tree
Hide file tree
Showing 9 changed files with 394 additions and 0 deletions.
13 changes: 13 additions & 0 deletions java/alb-multi-rule-response/.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

55 changes: 55 additions & 0 deletions java/alb-multi-rule-response/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<!--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 examples does is built on Construct Libraries marked "Stable" and does not have any infrastructure prerequisites to build.
---
<!--END STABILITY BANNER-->

# ALB using a combination of host and path based routing with Java AWS-CDK
The ALB is backed by an EC2 instance acting as frontend client and built-in ALB response rules that simulates mobile and application api

## Testing the responses
### testing mobile produciton api
``` bash
curl -H "Host: mobile.mydomain.com" [ALB-DNS-FQDN]/production
```
Resonse received
```json
{"status":"succes","apiversion":"prod_mobile_v1"}
```

### Testing frontend production api
``` bash
curl -H "Host: api.mydomain.com" [ALB-DNS-FQDN]/production
```

```json
{"status":"succes","apiversion":"prod_api_v1"}
```

## List of ALB rules
![alt text](imgs/screenshot.png "screenshot of resulting rule")


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.

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.
More information on ALB and Path routing is available here https://docs.aws.amazon.com/elasticloadbalancing/latest/application/tutorial-load-balancer-routing.html

The cdk.json file tells the CDK Toolkit how to execute your app. This example relies on maven to do that.

## Useful commands

* `mvn 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

Enjoy!
3 changes: 3 additions & 0 deletions java/alb-multi-rule-response/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "mvn -e -q exec:java"
}
Binary file added java/alb-multi-rule-response/imgs/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
69 changes: 69 additions & 0 deletions java/alb-multi-rule-response/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?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>albcdkproject</artifactId>
<version>0.1</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.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<mainClass>com.myorg.ALBProjectApp</mainClass>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<!-- AWS Cloud Development Kit -->
<dependency>
<groupId>software.amazon.awscdk</groupId>
<artifactId>core</artifactId>
<version>[1.26.0, 2)</version>
</dependency>

<dependency>
<groupId>software.amazon.awscdk</groupId>
<artifactId>elasticloadbalancingv2</artifactId>
<version>[1.26.0, 2)</version>
</dependency>
<dependency>
<groupId>software.amazon.awscdk</groupId>
<artifactId>ec2</artifactId>
<version>[1.26.0, 2)</version>
</dependency>
<dependency>
<groupId>software.amazon.awscdk</groupId>
<artifactId>autoscaling</artifactId>
<version>[1.26.0,2)</version>
</dependency>

<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.myorg;

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

public class ALBProjectApp {
public static void main(final String[] args) {
App app = new App();

new ALBProjectStack(
app, "ALBProjectStack", StackProps.builder().env(Environment.builder().build()).build());
app.synth();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package com.myorg;

import com.myorg.utils.PropertyLoader;
import java.util.ArrayList;
import java.util.List;
import software.amazon.awscdk.core.Construct;
import software.amazon.awscdk.core.Stack;
import software.amazon.awscdk.core.StackProps;
import software.amazon.awscdk.services.autoscaling.AutoScalingGroup;
import software.amazon.awscdk.services.ec2.AmazonLinuxImage;
import software.amazon.awscdk.services.ec2.InstanceClass;
import software.amazon.awscdk.services.ec2.InstanceSize;
import software.amazon.awscdk.services.ec2.InstanceType;
import software.amazon.awscdk.services.ec2.Vpc;
import software.amazon.awscdk.services.elasticloadbalancingv2.ApplicationListener;
import software.amazon.awscdk.services.elasticloadbalancingv2.ApplicationListenerRule;
import software.amazon.awscdk.services.elasticloadbalancingv2.ApplicationLoadBalancer;
import software.amazon.awscdk.services.elasticloadbalancingv2.ApplicationProtocol;
import software.amazon.awscdk.services.elasticloadbalancingv2.ApplicationTargetGroup;
import software.amazon.awscdk.services.elasticloadbalancingv2.ApplicationTargetGroupProps;
import software.amazon.awscdk.services.elasticloadbalancingv2.ContentType;
import software.amazon.awscdk.services.elasticloadbalancingv2.FixedResponse;
import software.amazon.awscdk.services.elasticloadbalancingv2.IApplicationLoadBalancerTarget;
import software.amazon.awscdk.services.elasticloadbalancingv2.IApplicationTargetGroup;
import software.amazon.awscdk.services.elasticloadbalancingv2.TargetType;

public class ALBProjectStack extends Stack {

public ALBProjectStack(final Construct scope, final String id) {
this(scope, id, null);
}

public ALBProjectStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);

// property loader
PropertyLoader propertyLoad = new PropertyLoader();

// create ALB and all anciliarry services
Vpc vpc = Vpc.Builder.create(this, "VPC").build();
AutoScalingGroup asg =
AutoScalingGroup.Builder.create(this, "ASG")
.vpc(vpc)
.instanceType(InstanceType.of(InstanceClass.BURSTABLE2, InstanceSize.MICRO))
.userData(propertyLoad.getUserData())
.machineImage(new AmazonLinuxImage())
.build();

ApplicationLoadBalancer lb =
ApplicationLoadBalancer.Builder.create(this, "LB")
.vpc(vpc)
.internetFacing(Boolean.TRUE)
.loadBalancerName("myalb")
.build();

List<IApplicationLoadBalancerTarget> targets = new ArrayList<IApplicationLoadBalancerTarget>();
targets.add(asg);

ApplicationTargetGroup webTargetGroup =
new ApplicationTargetGroup(
this,
"MyTargetGroup",
ApplicationTargetGroupProps.builder()
.vpc(vpc)
.targetType(TargetType.INSTANCE)
.targets(targets)
.port(80)
.protocol(ApplicationProtocol.HTTP)
.build());

List<IApplicationTargetGroup> targetGroups = new ArrayList<IApplicationTargetGroup>();
targetGroups.add(webTargetGroup);

// default listener
ApplicationListener http =
ApplicationListener.Builder.create(this, "HTTP")
.port(80)
.protocol(ApplicationProtocol.HTTP)
.open(true)
.loadBalancer(lb)
.defaultTargetGroups(targetGroups)
.build();

// adding application listern rules
ApplicationListenerRule alrProdApi =
ApplicationListenerRule.Builder.create(this, "prodApi")
.pathPattern("/production")
.priority(1)
.listener(http)
.hostHeader(propertyLoad.getRestAPIHostHeader())
.build();

ApplicationListenerRule alrProdM =
ApplicationListenerRule.Builder.create(this, "prodMobile")
.pathPattern("/production")
.priority(2)
.listener(http)
.hostHeader(propertyLoad.getRestMobileHostHeader())
.build();

ApplicationListenerRule alrSandboxApi =
ApplicationListenerRule.Builder.create(this, "sandboxApi")
.pathPattern("/sandbox")
.priority(3)
.listener(http)
.hostHeader(propertyLoad.getRestAPIHostHeader())
.build();

ApplicationListenerRule alrSandboxM =
ApplicationListenerRule.Builder.create(this, "sandboxMobile")
.pathPattern("/sandbox")
.priority(4)
.listener(http)
.hostHeader(propertyLoad.getRestMobileHostHeader())
.build();

// adding fixed responses
alrProdApi.addFixedResponse(
FixedResponse.builder()
.statusCode("200")
.contentType(ContentType.APPLICATION_JSON)
.messageBody(propertyLoad.getProdApiMessageBody())
.build());

alrProdM.addFixedResponse(
FixedResponse.builder()
.statusCode("200")
.contentType(ContentType.APPLICATION_JSON)
.messageBody(propertyLoad.getProdMobileMessageBody())
.build());

alrSandboxApi.addFixedResponse(
FixedResponse.builder()
.statusCode("200")
.contentType(ContentType.APPLICATION_JSON)
.messageBody(propertyLoad.getSandboxApiMessageBody())
.build());

alrSandboxM.addFixedResponse(
FixedResponse.builder()
.statusCode("200")
.contentType(ContentType.APPLICATION_JSON)
.messageBody(propertyLoad.getSandboxMobileMessageBody())
.build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.myorg.utils;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import software.amazon.awscdk.services.ec2.UserData;

public class PropertyLoader {

private final UserData userData;
private String prodMobileMessageBody;
private String prodApiMessageBody;
private String sandboxApiMessageBody;
private String sandboxMobileMessageBody;
private String restAPIHostHeader;
private String restMobileHostHeader;

public PropertyLoader() {
userData = UserData.forLinux();
load();
}

public UserData getUserData() {
return userData;
}

public String getProdMobileMessageBody() {
return prodMobileMessageBody;
}

public String getProdApiMessageBody() {
return prodApiMessageBody;
}

public String getSandboxApiMessageBody() {
return sandboxApiMessageBody;
}

public String getSandboxMobileMessageBody() {
return sandboxMobileMessageBody;
}

public String getRestAPIHostHeader() {
return restAPIHostHeader;
}

public String getRestMobileHostHeader() {
return restMobileHostHeader;
}

private void load() {
// start loading data from the properties files
try (InputStream input =
PropertyLoader.class.getClassLoader().getResourceAsStream("mydata.properties")) {

Properties prop = new Properties();
if (input == null) {
System.out.println("unable to find mydata.properties");
return;
}

// get the values from the properties file
prop.load(input);

// start populating values
prodMobileMessageBody = prop.getProperty("response.prodMobileV1");
prodApiMessageBody = prop.getProperty("response.prodApiV1");
sandboxApiMessageBody = prop.getProperty("response.sandboxApiV1");
sandboxMobileMessageBody = prop.getProperty("response.sandboxMobileV1");
restAPIHostHeader = prop.getProperty("rest.api");
restMobileHostHeader = prop.getProperty("rest.mobile");

String[] cmds = prop.getProperty("userData.commands").split("\n");
if (cmds.length > 0) {
for (String cmd : cmds) {
userData.addCommands(cmd);
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Loading

0 comments on commit 2216bf8

Please sign in to comment.