Skip to content

Commit 3a712bc

Browse files
committed
Merge branch 'lambda' into xray
2 parents fb852e0 + caabf96 commit 3a712bc

File tree

12 files changed

+238
-1
lines changed

12 files changed

+238
-1
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
Resources:
2+
RandomNameFunction:
3+
Type: "AWS::Lambda::Function"
4+
Properties:
5+
Code:
6+
ZipFile: "PLACEHOLDER"
7+
Description: "Generate random names"
8+
Environment:
9+
Variables:
10+
REGION_NAME: {"Ref" : "AWS::Region"}
11+
TOPIC_ARN: {"Ref" : "NotificationTopic"}
12+
FunctionName: random-name
13+
Handler: index.handler
14+
Role: { "Fn::Join": [ "", [ "arn:aws:iam::",{"Ref" : "AWS::AccountId"},":role/service-role/scorekeep-lambda" ] ] }
15+
Runtime: nodejs4.3
16+
17+
commands:
18+
install-npm:
19+
command: sudo -u ec2-user /tmp/install-npm.sh
20+
cwd: /home/ec2-user
21+
test: "[ ! -d /home/ec2-user/.nvm ]"
22+
23+
container_commands:
24+
update-random-name:
25+
command: /tmp/update-lambda.sh
26+
leader_only: true
27+
28+
files:
29+
"/tmp/install-npm.sh":
30+
mode: "000755"
31+
owner: ec2-user
32+
group: ec2-user
33+
content: |
34+
#!/bin/bash
35+
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash
36+
export NVM_DIR="$HOME/.nvm"
37+
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
38+
nvm install 4.3.2
39+
mkdir -p /home/ec2-user/bin
40+
ln -fs /home/ec2-user/.nvm/versions/node/v4.3.2/bin/npm /home/ec2-user/bin/npm
41+
ln -fs /home/ec2-user/.nvm/versions/node/v4.3.2/bin/node /home/ec2-user/bin/node
42+
43+
"/tmp/update-lambda.sh":
44+
mode: "000755"
45+
owner: ec2-user
46+
group: ec2-user
47+
content: |
48+
#!/bin/bash
49+
REGION=$(/opt/elasticbeanstalk/bin/get-config environment -k AWS_REGION)
50+
STAGINGDIR=$(/opt/elasticbeanstalk/bin/get-config container -k container_staging_dir)
51+
cd _lambda/random-name
52+
/home/ec2-user/bin/npm install
53+
zip -r ../random-name.zip *
54+
aws lambda update-function-code --function-name random-name --zip-file fileb://../random-name.zip --region $REGION

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ build/*
99
*.sh
1010
!bin/*.sh
1111
lib
12+
_lambda/random-name/node_modules/*

README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,62 @@
1+
# Lambda integration
2+
This branch uses a Node.js Lambda function to generate random names for new users, instead of calling a web API. The Scorekeep API uses the AWS SDK to invoke the Lambda by function name (`random-name`) with Bean classes to represent (and serialize to/from) the input and output JSON.
3+
4+
5+
## Configuration
6+
A CloudFormation template and [AWS CLI](http://docs.aws.amazon.com/cli/latest/userguide/installing.html) scripts to create and delete the function's execution role are included in the `_lambda` folder:
7+
- `_lambda/lambda-role.yml` - Template that defines the role
8+
- `_lambda/create-lambda-role.sh` - Script to create the role
9+
- `_lambda/delete-lambda-role.sh` - Script to delete the role
10+
11+
Run the script to create the role:
12+
eb-java-scorekeep/_lambda$ ./create-lambda-role.sh
13+
14+
If you don't have the AWS CLI, use the CloudFormation console to create a stack with the template.
15+
16+
Next, add the following policy to your instance profile ([aws-elasticbeanstalk-ec2-role](https://console.aws.amazon.com/iam/home#/roles/aws-elasticbeanstalk-ec2-role)) to let the environment create the Lambda function:
17+
- AWSLambdaFullAccess
18+
19+
Deploy this branch to your Elastic Beanstalk environment. No further configuration is required.
20+
If you don't have an environment, see below.
21+
22+
## Implementation
23+
The Lambda function code is included in `_lambda/random-name/index.js`. On deploy, configuration files in the .ebextensions folder create a function with the following settings:
24+
- Name: `random-name`
25+
- Runtime: Node.js 4.3
26+
- Description: `Generate random names`
27+
- Code: in `_Lambda/random-name`
28+
- Environment variables:
29+
- REGION_NAME: The region, e.g. `us-east-2`
30+
- TOPIC_ARN: The ARN of an [SNS Topic](https://console.aws.amazon.com/sns/v2/home)
31+
- Role named "scorekeep-lambda"
32+
33+
The role named "scorekeep-lambda" has the following policies:
34+
- Managed policy - AWSLambdaBasicExecutionRole
35+
- Managed policy - AmazonSNSFullAccess
36+
- Managed policy - AWSXrayWriteOnlyAccess (optional) for compatibility with the xray branch
37+
- Trust policy -
38+
39+
{
40+
"Version": "2012-10-17",
41+
"Statement": [
42+
{
43+
"Effect": "Allow",
44+
"Principal": {
45+
"Service": "lambda.amazonaws.com"
46+
},
47+
"Action": "sts:AssumeRole"
48+
}
49+
]
50+
}
51+
52+
The Scorekeep API integration is implemented in the following files-
53+
`src/main/java/scorekeep/`
54+
- `RandomNameInput.java` - Bean for the input, a user ID and category.
55+
- `RandomNameOutput.java` - Bean for the output, a first name.
56+
- `RandomNameService.java` - Defines the method used to call the Lambda function. Combined with an AWS SDK Lambda client to create a Lambda Invoker.
57+
- `UserFactory.java` - **UserFactory.randomNameLambda** Creates the Lambda Invoker with `com.amazonaws.services.lambda.invoke.LambdaInvokerFactory`. Calls the Lambda function to generate a random name.
58+
- `build.gradle` - Adds the Lambda module of the AWS SDK to the Gradle build.
59+
160
# Scorekeep
261
Scorekeep is a RESTful web API implemented in Java that uses Spring to provide an HTTP interface for creating and managing game sessions and users. This project includes the scorekeep API and a frontend web app that consumes it. The frontend and API can run on the same server and domain or separately, with the API running in Elastic Beanstalk and the frontend served statically by a CDN.
362

_lambda/lambda-role.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Resources:
2+
RandomNameRole:
3+
Type: "AWS::IAM::Role"
4+
Properties:
5+
AssumeRolePolicyDocument: {
6+
"Version": "2012-10-17",
7+
"Statement": [
8+
{
9+
"Effect": "Allow",
10+
"Principal": {
11+
"Service": "lambda.amazonaws.com"
12+
},
13+
"Action": "sts:AssumeRole"
14+
}
15+
]
16+
}
17+
ManagedPolicyArns:
18+
- arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess
19+
- arn:aws:iam::aws:policy/AmazonSNSFullAccess
20+
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
21+
Path: /service-role/
22+
RoleName: scorekeep-lambda

_lambda/random-name/index.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
var AWS = require('aws-sdk');
2+
AWS.config.update({region: process.env.REGION});
3+
var Chance = require('chance');
4+
5+
var myFunction = function(event, context, callback) {
6+
var sns = new AWS.SNS();
7+
var chance = new Chance();
8+
var userid = event.userid;
9+
10+
var name = chance.first();
11+
12+
// Nofity
13+
var params = {
14+
Message: 'Created randon name "' + name + '"" for user "' + userid + '".',
15+
Subject: 'New user: ' + name,
16+
TopicArn: process.env.TOPIC_ARN
17+
};
18+
sns.publish(params, function(err, data) {
19+
if (err) {
20+
console.log(err, err.stack);
21+
callback(err);
22+
}
23+
else {
24+
console.log(data);
25+
callback(null, {"name": name});
26+
}
27+
});
28+
};
29+
30+
exports.handler = myFunction;

_lambda/random-name/package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "random-name",
3+
"version": "1.0.0",
4+
"description": "Name generator",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "eb-java-scorekeep"
12+
},
13+
"author": "mwunderl",
14+
"license": "Apache-2.0",
15+
"dependencies": {
16+
"chance": "^1.0.4",
17+
"aws-xray-sdk": "1.1.0"
18+
}
19+
}

_lambda/update-random-name.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/bash
2+
cd random-name
3+
npm install
4+
zip -r ../random-name.zip *
5+
aws lambda update-function-code --function-name random-name --zip-file fileb://../random-name.zip

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ dependencies {
3131
compile("org.springframework.boot:spring-boot-starter-data-jpa")
3232
testCompile("org.springframework.boot:spring-boot-starter-test")
3333
compile("com.amazonaws:aws-java-sdk-dynamodb")
34+
compile("com.amazonaws:aws-java-sdk-lambda")
3435
compile("com.amazonaws:aws-java-sdk-sns")
3536
compile("com.amazonaws:aws-xray-recorder-sdk-core")
3637
compile("com.amazonaws:aws-xray-recorder-sdk-aws-sdk")
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package scorekeep;
2+
3+
public class RandomNameInput {
4+
private String category;
5+
private String userid;
6+
7+
public String getCategory() { return category; }
8+
public void setCategory(String value) { category = value; }
9+
10+
public String getUserid() { return userid; }
11+
public void setUserid(String value) { userid = value; }
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package scorekeep;
2+
3+
public class RandomNameOutput {
4+
private String name;
5+
public String getName() { return name; }
6+
public void setName(String value) { name = value; }
7+
}

0 commit comments

Comments
 (0)