Skip to content

Commit

Permalink
mParticle Integration - Final Updates (#276)
Browse files Browse the repository at this point in the history
* mParticle workshop and code

This  contains the code to set the environment variables, handle mParticle logic within the analyticshandler.js and include the main npm module within the main.js

* update workshop

* Added lambda and cf templates

* Updated bundle for mparticle lambda

* Added environment variables for lambda

* Added campaign arn parameter to lambda

* Updates to CF template for lambdas

* Added mParticle API keys to master template

* Updated go mod file for lambda deployment

* Removed encryption tag

* Spelling error fix

* Removed docs ref to manual Go deps install

* Add all npm deps to lambda

* Added conda_python3 env to mParticle notebook

* Added workshops to the main README page

* Added mParticle logo SVG

* Corrected link to Real Time Events notebook

* Updated events workshop to support SSM parameters

* Updated roles and CF parameters to conform to original workshop

* Corrected org id spelling and deleted mp trust role

* Role syntax error fix

* Added string subs for role resources

* Set events wkshop notebook to conda_python3

* Added unique name for cross-account role

* Added IAM update role permissions to support changes

* Added branch to sagemaker git deploys

* Added github branch to base template

* Default branch is set to 'master'

* CodeRepositoryUrl added

* Added stream name and region spec

* Fixed role update code

* Fixed repeated content

* Update Analytics Handler 

Add missing variables

* Update AnalyticsHandler.js

cart quantity variable is missing

* Update mParitcle Real Time Events Documentation

Update mParitcle Real Time Events Documentation

* Updated Jupyter notebooks for mParticle

Updated Jupyter notebooks for mParticle

* Added mP params + removed cell outputs in ipynb

* buildspec params for webui

* Removed keys from CF and into buildspec.yml

* changes mP SSM variables to conform to best practices

* fixed role creation permissions and code

* Added delete step for roles created in mP workshop

* all caps lambda envs and replaced lambda code

* Add Enable Kinesis Stream Screenshot in Lambda

Add Enable Kinesis Stream Screenshot in Lambda

* Add Enable Kinesis Stream Screenshot in Lambda

Add Enable Kinesis Stream Screenshot in Lambda

* Update mParticle docs to format images and include additional step to enable AWS Kinesis component in Lambda

Update mParticle docs to format images and include additional step to enable AWS Kinesis component in Lambda

* Format pictures to standardized dimensions

* Added license statement to mp js code

* Refactor variable names and move globals to function scope

* notbook github repo name mapped to stack and region

* Uid passed to mp resource names for same account deploys

* Reformatted for style + removed console.log

* Stylistic changes plus review comment

* Fixed Uids for notebook repos and mP resources

* Removed console.log from Analytics library

* Replaced static cart IDs with cart.id

* Editing mP Lambda JS code

* Added services url ssm and lookup code in lambda

* Fixed SSM params

* Remove mParticle OrgID default value from base templates

* Added SSM params for mP Lambda function

* Fix param passing to base template

* Shrank mP Lambda package; update to perms for SSM

* Added SSM param reads to mP lambda

* Product URL fix

* Clarifying comment

* Synced params to mParticle notebook

* Updated instructions to use SSM parameters

* missing mParticle params

missing mParticle params

* Update Readme md mParticle section

Update Readme md mParticle section

* Update workshop email contact and code

Update workshop email contact and code

* Update mailto markdown

* Update mail to link

* Update Mail To

* Fixed some syntax errors; variable naming

* Proposed changes to lambda structure

* Update mParticle-personalize.js 

Support async function

* Update mparticle-personalize.js

Updated Code

* Update mParticle-personalize.js

Revert back to using const personalizeRuntime = new AWS.PersonalizeRuntime(); as the new code introduced by Igor was throwing errors.

* Update workshop to support new changes

Update workshop to support new changes

* Updated lambda code to use async/await

* Update mparticle-personalize.js

Updated lambda hanlder using Igor's code and Jeff's code.

* Update workshop

Update workshop with recent changes

* Update Workshop mParticle Personalize

Update IAM Creation Policy step

* Update workshop

Clear outputs

* Refactor last part of code for mP calls

* Removed checked-in s2s keys from code

* Update mparticle-perosnalize.js

trackingID renamed to personalizeTrackerID. 
Remove discount

* Add image to workshop

Add Kinesis Component Screenshot

* Update workshop

Added new screenshots

* Fixed resource policies

* Update mparticle-personalize.js

Fixes as per Jame's feedback/comments. PR comment - #276

* Replaced npm install with npm ci

* remove unused env variables for mp lambda

* Added mP S2S params to top of master template

Co-authored-by: hawjefferson <[email protected]>
  • Loading branch information
manbearshark and hawjefferson authored Dec 7, 2021
1 parent 695bbac commit 9e31800
Show file tree
Hide file tree
Showing 92 changed files with 2,189 additions and 19 deletions.
11 changes: 1 addition & 10 deletions Developer-Instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,7 @@ If you plan to enable the automated Personalize campaign creation process at dep

It is advisable to use a Python 3 virtual environment to do this and the scripts assume that the executable pip is the Python 3 version of pip so if necessary you may need to install pip into that virtual environment (if your system defaults to a Python 2 version of pip).

There are also some Golang dependencies that need to be installed before staging:

```bash
go get github.com/aws/aws-lambda-go/lambda
go get github.com/aws/aws-lambda-go/cfn
go get github.com/aws/aws-sdk-go
go get gopkg.in/yaml.v2
```

The [stage.sh](stage.sh) script at the root of the repository must be used to upload the deployment resources to your staging S3 bucket if you use this option. The shell uses the local AWS credentials to build and push resources to your custom bucket.
The [stage.sh](stage.sh) script at the root of the repository must be used to upload the deployment resources to your staging S3 bucket if you use this option. The shell uses the local AWS credentials to build and push resources to your custom bucket.

Example on how to stage your project to a custom bucket and path (note the path is optional but, if specified, must end with '/'):

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ AWS Partner | Workshops Overview | Workshop Links | Level | Duration
--- | --- | --- | --- | ---
<img src="./workshop/images/amplitude.svg" height=64px/> | In this workshop, you will set up tracking for [Amplitude](https://amplitude.com/) events, analyze user behavior prior to peronalization being deployed, and then measure the effects of personalization on user behavior after Personalize is deployed in the Retail Demo Store. | [Evaluating Personalization Performance](./workshop/3-Experimentation/3.5-Amplitude-Performance-Metrics.ipynb) | 200 | 30 minutes
<img src="./workshop/images/braze.svg" height=64px/> | In this workshop we will use [Braze](https://www.braze.com/) to add the ability to personalize marketing messages to customers of the Retail Demo Store using customer behavioral data and the Personalize models you trained when setting up Amazon Personalize. | [Personalized Email Campaigns](./workshop/4-Messaging/4.2-Braze.ipynb) | 200 | 1 hour
<img src="./workshop/images/mparticle.svg" height=64px/> | [mParticle](https://mparticle.com/) is the largest indepedent Customer Data Platform that allows any brand to ingest data from any and multiple sources in real-time, apply data quality and governance over the ingested data and orchestrate the data to any marketing and technology stack your organization is using. In this workshop, you will configure real-time event flows to Amazon Personalize using the mParticle SDKs and then use that data to create customer profiles that can be used in marketing campaigns to customers via Braze. | [Real Time Personalization Events](./workshop/1-Personalization/1.2-Real-Time-Events-mParticle.ipynb) <br/><br/> [Personalized Customer Profiles and Messaging with any marketing tool (Braze) and mParticle](./workshop/6-CustomerDataPlatforms/6.3-mParticleBraze.ipynb) | 300 | 1-1.5 hours
<img src="./workshop/images/optimizely.svg" height=64px/> | In this exercise we will define, launch, and evaluate the results of an A/B experiment of a personalized user experience using [Optimizely](https://www.optimizely.com/). | [AB Experiments for Personalization](./workshop/3-Experimentation/3.6-Optimizely-AB-Experiment.ipynb) | 200 | 30 minutes
<img src="./workshop/images/segment.svg"/> | [Segment](https://segment.com/) is a real-time events pipeline for customer data, as well as a customer data platform. In the Retail Demo Store, Segment is used to deliver real-time events from the web user interface to Amazon Personalize. These real-time events are also used to create customer profile with Amazon Personalize recommendations appended, which can then be used via the CDP to push data to marketing tools. | [Real Time Personalization Events](./workshop/1-Personalization/1.2-Real-Time-Events-Segment.ipynb) <br/><br/> [Customer Data Platforms and Personalize](./workshop/6-CustomerDataPlatforms/6.1-Segment.ipynb) | 300 | 1-1.5 hours

Expand Down
35 changes: 35 additions & 0 deletions aws/cloudformation-templates/base/_template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,31 @@ Parameters:
Description: Segment source write key (optional).
NoEcho: true

mParticleOrgId:
Type: String
Description: mParticle Org Id
NoEcho: true

mParticleApiKey:
Type: String
Description: mParticle API Key.
NoEcho: true

mParticleSecretKey:
Type: String
Description: mParticle Secret Key.
NoEcho: true

mParticleS2SApiKey:
Type: String
Description: mParticle server to server API Key.
NoEcho: true

mParticleS2SSecretKey:
Type: String
Description: mParticle server to server Secret Key.
NoEcho: true

PinpointSMSLongCode:
Type: String
Description: Pinpoint SMS Long code.
Expand All @@ -73,6 +98,10 @@ Parameters:
Type: String
Description: Your GitHub username.

GitHubBranch:
Type: String
Description: The GitHub branch used for deployment.

Resources:

# Authentication
Expand Down Expand Up @@ -109,6 +138,7 @@ Resources:
UserPoolId: !GetAtt Authentication.Outputs.UserPoolId
PinpointAppId: !GetAtt Pinpoint.Outputs.PinpointAppId
GitHubUser: !Ref GitHubUser
GitHubBranch: !Ref GitHubBranch

# Tables
Tables:
Expand Down Expand Up @@ -187,6 +217,11 @@ Resources:
AmplitudeApiKey: !Ref AmplitudeApiKey
OptimizelySdkKey: !Ref OptimizelySdkKey
SegmentWriteKey: !Ref SegmentWriteKey
mParticleOrgId: !Ref mParticleOrgId
mParticleApiKey: !Ref mParticleApiKey
mParticleSecretKey: !Ref mParticleSecretKey
mParticleS2SApiKey: !Ref mParticleS2SApiKey
mParticleS2SSecretKey: !Ref mParticleS2SSecretKey
PinpointSMSLongCode: !Ref PinpointSMSLongCode
GoogleAnalyticsMeasurementId: !Ref GoogleAnalyticsMeasurementId

Expand Down
38 changes: 35 additions & 3 deletions aws/cloudformation-templates/base/notebook.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Parameters:
Type: String
Description: Your GitHub username.

GitHubBranch:
Type: String
Description: The GitHub branch to use for deployments.

Subnets:
Type: String

Expand Down Expand Up @@ -45,6 +49,15 @@ Conditions:
- ''

Resources:
RetailDemoStoreGitHubRepo:
Type: AWS::SageMaker::CodeRepository
Properties:
CodeRepositoryName: !Sub '${Uid}-retail-demo-store'
GitConfig:
Branch: !Ref GitHubBranch
RepositoryUrl: !Sub
- 'https://github.com/${User}/retail-demo-store.git'
- { User: !If [ UseDefaultGitHubUser, 'aws-samples', !Ref GitHubUser ] }
NotebookInstance:
Type: AWS::SageMaker::NotebookInstance
Properties:
Expand All @@ -54,9 +67,7 @@ Resources:
SubnetId: !Ref Subnet1
SecurityGroupIds:
- !Ref SecurityGroup
DefaultCodeRepository: !Sub
- 'https://github.com/${User}/retail-demo-store.git'
- { User: !If [ UseDefaultGitHubUser, 'aws-samples', !Ref GitHubUser ] }
DefaultCodeRepository: !Sub '${Uid}-retail-demo-store'
Tags:
-
Key: "Uid"
Expand Down Expand Up @@ -166,6 +177,27 @@ Resources:
- iam:DetachRolePolicy
- iam:DeleteRole
Resource: !Sub 'arn:aws:iam::${AWS::AccountId}:role/${Uid}-PersonalizeS3'
-
Effect: "Allow"
Action:
- iam:UpdateAssumeRolePolicy
Resource: !Sub 'arn:aws:iam::${AWS::AccountId}:role/${AWS::Region}-mParticleKinesisCrossAccountRole'
-
Effect: "Allow"
Action:
- iam:CreatePolicy
- iam:DeletePolicy
Resource: !Sub 'arn:aws:iam::${AWS::AccountId}:policy/KinesismParticlePolicy'
-
Effect: "Allow"
Action:
- iam:CreateUser
- iam:DeleteUser
- iam:AttachUserPolicy
- iam:DetachUserPolicy
- iam:CreateAccessKey
- iam:DeleteAccessKey
Resource: !Sub 'arn:aws:iam::${AWS::AccountId}:user/mParticleRetailDemoStoreKinesis'
-
Effect: Allow
Action:
Expand Down
75 changes: 75 additions & 0 deletions aws/cloudformation-templates/base/ssm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,31 @@ Parameters:
Description: Write key for the Segment source used to gather real-time events (optional).
NoEcho: true

mParticleOrgId:
Type: String
Description: mParticle Org ID from your mParticle workspace.
NoEcho: true

mParticleApiKey:
Type: String
Description: mParticle front end API Key
NoEcho: true

mParticleSecretKey:
Type: String
Description: mParticle front end secret key
NoEcho: true

mParticleS2SApiKey:
Type: String
Description: mParticle server to server API Key
NoEcho: true

mParticleS2SSecretKey:
Type: String
Description: mParticle server to server secret key
NoEcho: true

PinpointSMSLongCode:
Type: String

Expand All @@ -40,6 +65,16 @@ Conditions:
!Not [!Equals [!Ref OptimizelySdkKey, ""]]
HasSegmentWriteKey:
!Not [!Equals [!Ref SegmentWriteKey, ""]]
HasmParticleOrgId:
!Not [!Equals [!Ref mParticleOrgId, ""]]
HasmParticleApiKey:
!Not [!Equals [!Ref mParticleApiKey, ""]]
HasmParticleSecretKey:
!Not [!Equals [!Ref mParticleSecretKey, ""]]
HasmParticleS2SApiKey:
!Not [!Equals [!Ref mParticleS2SApiKey, ""]]
HasmParticleS2SSecretKey:
!Not [!Equals [!Ref mParticleS2SSecretKey, ""]]
HasPinpointSMSLongCode:
!Not [!Equals [!Ref PinpointSMSLongCode, ""]]
HasGoogleAnalyticsMeasurementId:
Expand Down Expand Up @@ -160,6 +195,46 @@ Resources:
Value: !If [HasSegmentWriteKey, !Ref SegmentWriteKey, 'NONE']
Description: "Retail Demo Store Segment source write key"

ParametermParticleOrgId:
Type: "AWS::SSM::Parameter"
Properties:
Name: "retaildemostore-mparticle-org-id"
Type: "String"
Value: !If [HasmParticleOrgId, !Ref mParticleOrgId, 'NONE']
Description: "Retail Demo Store mParticle org id"

ParametermParticleApiKey:
Type: "AWS::SSM::Parameter"
Properties:
Name: "/retaildemostore/webui/mparticle_api_key"
Type: "String"
Value: !If [HasmParticleApiKey, !Ref mParticleApiKey, 'NONE']
Description: "Retail Demo Store mParticle API key"

ParametermParticleSecretKey:
Type: "AWS::SSM::Parameter"
Properties:
Name: "/retaildemostore/webui/mparticle_secret_key"
Type: "String"
Value: !If [HasmParticleSecretKey, !Ref mParticleSecretKey, 'NONE']
Description: "Retail Demo Store mParticle secret key"

ParametermParticleS2SApiKey:
Type: "AWS::SSM::Parameter"
Properties:
Name: "/retaildemostore/webui/mparticle_s2s_api_key"
Type: "String"
Value: !If [HasmParticleS2SApiKey, !Ref mParticleS2SApiKey, 'NONE']
Description: "Retail Demo Store mParticle server to server API key - used for Kinesis processing"

ParametermParticleS2SSecretKey:
Type: "AWS::SSM::Parameter"
Properties:
Name: "/retaildemostore/webui/mparticle_s2s_secret_key"
Type: "String"
Value: !If [HasmParticleS2SSecretKey, !Ref mParticleS2SSecretKey, 'NONE']
Description: "Retail Demo Store mParticle server to server secret key - used for Kinesis processing"

ParameterPinpointSMSLongCode:
Type: "AWS::SSM::Parameter"
Properties:
Expand Down
129 changes: 129 additions & 0 deletions aws/cloudformation-templates/mparticle.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
---
AWSTemplateFormatVersion: 2010-09-09

Description: >
This template deploys a Kinesis stream and two Lambda functions for use with the Amazon Personalize destination
in the Personalize and CDP workshops, along with the execution roles required to run the Lambda and for mParticle
to be able to access the Lambda from the Personalize destination.
Parameters:
ResourceBucket:
Type: String
Description: >
S3 bucket name where the Retail Demo Store deployment resources are staged (product images, nested CloudFormation templates, source code snapshot,
notebooks, deployment Lambda code, etc). You can substitute your own bucket here if needed.
ResourceBucketRelativePath:
Type: String
Description: >
Optional path in the Deployment Resources Staging bucket where the deployment resources are stored (e.g. path/path2/).
Leave blank if resources are at the root of the Staging Resource Bucket. If specified, MUST end with '/'.
Uid:
Type: String
Description: >
Uid generated from the root template to provide unique resource names
mParticleOrgId:
Type: String
Description: >
The OrgID for your mParticle instance. This will be used to enable assume role for mParticle to write to Kinesis.
Resources:
mParticlePersonalizeEventsKinesisStream:
Type: AWS::Kinesis::Stream
Properties:
Name: !Sub '${Uid}-mParticlePersonalizeEventsKinesisStream'
ShardCount: 1

mParticlePersonalizeLambda:
Type: 'AWS::Lambda::Function'
Properties:
Description: 'Handles sending events passed from mParticle to the Personalize tracker for user-item interactions.'
Handler: mparticle-personalize.handler
Role: !GetAtt
- mParticlePersonalizeLambdaExecutionRole
- Arn
Code:
S3Bucket: !Ref ResourceBucket
S3Key: !Sub '${ResourceBucketRelativePath}aws-lambda/mparticle-personalize.zip'
Runtime: nodejs12.x
Timeout: 900
FunctionName: !Sub '${Uid}-mParticlePersonalizeLambda'

mParticleKinesisCrossAccountRole:
Type: 'AWS::IAM::Role'
Properties:
RoleName: !Sub '${Uid}-mParticleKinesisCrossAccountRole'
Description: 'Allows mParticle to write messages to your Kinesis stream.'
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS:
- "arn:aws:iam::338661164609:role/role-lambda-verifyrequest"
- "arn:aws:iam::338661164609:role/role-ecs-mp-notification-httpservertoserverprocessor"
Action:
- 'sts:AssumeRole'
Condition:
StringEquals:
"sts:ExternalId": !Sub 'orgid:${mParticleOrgId}'
Path: /
Policies:
- PolicyName: root
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'kinesis:PutRecord'
Resource:
- !Sub 'arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/${Uid}-mParticlePersonalizeEventsKinesisStream'

mParticlePersonalizeLambdaExecutionRole:
Type: 'AWS::IAM::Role'
Properties:
Description: 'Execution role for the Lambda provided with the mParticle workshop.'
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AWSLambdaKinesisExecutionRole'
Policies:
- PolicyName: root
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${Uid}-mParticlePersonalizeLambda*:log-stream:*'
- !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${Uid}-mParticlePersonalizeLambda*'
- Effect: Allow
Action:
- ssm:GetParameter
- ssm:GetParameters
Resource:
- !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/retaildemostore-*'
- !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/retaildemostore*'
- Effect: Allow
Action:
- logs:CreateLogGroup
- personalize:GetRecommendations
- personalize:PutEvents
Resource: '*'

Outputs:
mParticlePersonalizeLambdaFunctionArn:
Description: Lambda function ARN for the mParticle Personalize Lambda function.
Value: !GetAtt mParticlePersonalizeLambda.Arn
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ Resources:
- Key: deregistration_delay.timeout_seconds
Value: '30'

# Loadbalancer SSM Parameter
ServicesLoadBalancerSSMParameter:
Type: "AWS::SSM::Parameter"
Properties:
Name: !Sub "/retaildemostore/services_load_balancers/${ServiceName}"
Type: "String"
Value: !Sub http://${LoadBalancer.DNSName}
Description: !Sub "Load balancer URL for the Retail Demo Store ${ServiceName} service"

Outputs:
TargetGroup:
Description: Target Group for Web UI Service Instances
Expand Down
Loading

0 comments on commit 9e31800

Please sign in to comment.