An Amazon Lex V2 CloudFormation Custom Resource
NOTE: this project has been deprecated. Amazon Lex now supports AWS CloudFormation.
Before you can use the Custom Resource, you need to deploy this project in your AWS account. You can deploy this project using the AWS Serverless Application Repository (SAR) or using the AWS Serverless Application Model Command Line Interface (SAM CLI). Once you deploy it, you can reference the created Lambda function and IAM role in your CloudFormation templates. See the Usage section below for details on how to use the Custom Resources.
Deployment options:
-
Using SAR:
You can deploy this project with this AWS Console one click link.
Alternatively, you can directly embed the SAR application as a nested stack in your CloudFormation template. See the following snippet or the examples/zip-code directory for a template that uses this nested stack approach.
NOTE: Deploying the stack with the one click SAR link above is preferred over using the nested stack in cases where you want a single instance of the Custom Resource Lambda function to be shared between stacks to avoid duplication.
Resources: # This deploys the Custom Resource as a nested CloudFormation stack # The Custom Resource is provisioned with your bot. However, the Custom # Resource becomes dedicated and should not be shared with other stacks # as it gets deleted when you delete your stack LexV2CfnCr: Type: AWS::Serverless::Application Properties: Location: ApplicationId: arn:aws:serverlessrepo:us-east-1:777566285978:applications/lex-v2-cfn-cr SemanticVersion: 0.3.0 Parameters: # Custom Resource Lambda log level LogLevel: 'INFO' LexBot: Type: Custom::LexBot Properties: # this references the Lambda function created by the Custom Resource stack above. # Note that it uses the Outputs of the nested stack ServiceToken: !GetAtt LexV2CfnCr.Outputs.LexV2CfnCrFunctionArn botName: My Bot # ... # See the example in the examples/zip-code directory for a full template # that uses this approach
-
Using the SAM CLI:
Clone this repo and issue the following commands from a host with the sam cli:
sam build --use-container sam deploy --guided
See the examples/order-flowers directory for a template that illustrates how to use this approach. See the Development section below for more details.
Once you have deployed the Custom Resource stack as described above, you are ready to use it in your own CloudFormation templates. There are three Custom Resources that work together:
- LexBot: Deploys a Lex bot including associated subresources: locales,
slot types, intents and slots. These subresources are managed as a unit with
the bot so everything is managed from a single resource. CloudFormation
changes are done to the
DRAFT
version of the bot. The Custom Resource automatically builds all locales after successful CloudFormation deployments - LexBotVersion: Creates immutable bot versions from the bot
DRAFT
version - LexBotAlias: Provisions and manages a bot alias that is pointed to a version
The snippett below shows an example of how to use these Custom Resources in your CloudFormation templates:
Parameters:
# add a parameter to your bot template to reference the Custom Resource stack
LexV2CfnCrStackName:
Description: >-
Existing Lex V2 Custom Resource Stack Name. This is used to import the
Lambda function and IAM role provisioned by the Custom Resource stack
Type: String
# If you deployed via the SAR Console and used the defaults, your stack
# will be named serverlessrepo-lex-v2-cfn-cr. If you deployed manually,
# make it match the name of your Custom Resource stack
Default: serverlessrepo-lex-v2-cfn-cr
Resources:
# LexBot resource contains the bot definition and subresources including:
# locales, slot types, intents and slots. These subresources use custom
# attributes with a name prefix: CR.<subresource name>
# The changes are done to the DRAFT version of the bot.
# All locales are automatically built
LexBot:
Type: Custom::LexBot
Properties:
ServiceToken:
# Points to the Custom Resource Lambda function
!ImportValue
Fn::Sub: "${LexV2CfnCrStackName}-LexV2CfnCrFunctionArn"
# Bot level attributes
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lexv2-models.html#LexModelsV2.Client.create_bot
botName:
ZipCodeUpdateBot
dataPrivacy:
childDirected: True
description: Test bot deployed using CloudFormation Custom Resource
idleSessionTTLInSeconds: 300
roleArn:
# Points to the Custom Resource IAM Service Linked role
!ImportValue
Fn::Sub: "${LexV2CfnCrStackName}-LexServiceLinkedRole"
# List of Bot Locale definitions. Requires one or more locales
CR.botLocales:
# Locale level attributes
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lexv2-models.html#LexModelsV2.Client.create_bot_locale
- localeId: en_US
nluIntentConfidenceThreshold: 0.40
voiceSettings:
voiceId: Salli
# List of optional Slot Type definitions
CR.slotTypes:
# Slot Type level attributes
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lexv2-models.html#LexModelsV2.Client.create_slot_type
- slotTypeName: ZipCodeType
parentSlotTypeSignature: AMAZON.AlphaNumeric
valueSelectionSetting:
resolutionStrategy: OriginalValue
regexFilter:
pattern: '[0-9]{8}'
# List of Intent definitions. Requires one or more Intents
CR.intents:
# Intent level attributes
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lexv2-models.html#LexModelsV2.Client.create_intent
- intentName: UpdateZipCode
sampleUtterances:
- utterance: i want to change my zip code
- utterance: i have a new zip code
- utterance: my new zip code is {ZipCode}
# List of optional Slot definitions. Defined in order of slot priority
CR.slots:
# Slot level attributes
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lexv2-models.html#LexModelsV2.Client.create_slot
- slotName: ZipCode
# Slot Type Name is used to dyanmically resolve the ID of the
# associated Slot Type defined above
CR.slotTypeName: ZipCodeType
valueElicitationSetting:
slotConstraint: Required
promptSpecification:
messageGroups:
- message:
plainTextMessage:
value: What is your zipcode?
maxRetries: 2
allowInterrupt: true
# The Fallback intent is automatically created by the Lex service
# This will update the default fallback intent
- intentName: FallbackIntent
description: Default fallback intent when no other intent matches
intentClosingSetting:
closingResponse:
messageGroups:
- message:
plainTextMessage:
value: Sorry I am having trouble understanding.
# Creates an immutable Bot Version
LexBotVersion:
# Bot versions are deleted by the Bot on Stack deletions. This deletion
# policy speeds up deletes
DeletionPolicy: Retain
# Version number changes between updates which cause a CloudFormation
# delete event since the version number is the physical resource ID.
# The following policies prevents deletion events to retain the bot versions
# and speed up updates
UpdateReplacePolicy: Retain
Type: Custom::LexBotVersion
Properties:
ServiceToken:
!ImportValue
Fn::Sub: "${LexV2CfnCrStackName}-LexV2CfnCrFunctionArn"
# Bot Version level attributes
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lexv2-models.html#LexModelsV2.Client.create_bot_version
botId: !Ref LexBot
# botVersionLocaleSpecification is derived from the bot locales
# this controls which locales are added to the version
CR.botLocaleIds: !GetAtt LexBot.botLocaleIds
# lastUpdatedDateTime is used to detect changes in the bot
CR.lastUpdatedDateTime: !GetAtt LexBot.lastUpdatedDateTime
# Provisions a Bot Alias that points to a version
LexBotAlias:
# Bot aliases are deleted by the Bot on Stack deletions. This deletion
# policy speeds up deletes
DeletionPolicy: Retain
Type: Custom::LexBotAlias
Properties:
ServiceToken:
!ImportValue
Fn::Sub: "${LexV2CfnCrStackName}-LexV2CfnCrFunctionArn"
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lexv2-models.html#LexModelsV2.Client.create_bot_alias
botId: !Ref LexBot
botAliasName: live
# points to the latest version of the resource above
botVersion: !Ref LexBotVersion
# enable locales under this alias
botAliasLocaleSettings:
en_US:
enabled: True
Outputs:
LexBotId:
Description: Lex Bot ID
Value: !Ref LexBot
LexBotLocaleIds:
Description: Lex Bot Locale IDs
Value: !Join [",", !GetAtt LexBot.botLocaleIds]
LexBotLatestVersion:
Description: Latest Lex Bot Version ID
Value: !Ref LexBotVersion
LexBotAliasId:
Description: Lex Bot Alias ID
Value: !Ref LexBotAlias
Generally, the Custom Resources proxy the requests to the corresponding Create/Update/Delete operations of the Lex V2 Models API using boto3. For details, see the boto3 Lex V2 Models reference
Some attributes of the custom resources use the prefix CR.
as a marker for
subresources (e.g. locales, slot types, intents, slots).
It is also used for cases where the underlying API requires an ID that needs to
be dynamically resolved and for custom attributes that are not part of the
Lex APIS.
- CloudFormation update and creation events must complete within the Lambda limit of 15 minutes. This also includes building the Bot locales. This is enough time for the vast majority of bots. The poller functionality of the CrHelper library is not used to extend this time since larger bot definitions can trigger a 8KB limit in the CloudWatch Events input payload
- If a bot fails to build during a deployment, it may not be able to
automatically roll back the
DRAFT
version. In that case, you may need to restore theDRAFT
version manually and rebuild before you can update with CloudFormation again. You can also use the Lex export functionality to an get an existing working bot version and restore it into the currentDRAFT
using the Lex import functionality - Lex Bot Resource Policies are not implemented
- The Custom Resource stack deploys a regular IAM Role instead of an IAM Service Linked Role to be used with the Lex Bot. The SAR service does not currently support Service Linked Roles. We may change this if support is added. You can create your own Service Linked Role separately and use it in your template
The deployment of this project uses the SAM CLI.
The SAM CLI is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda.
To use the SAM CLI, you need the following tools.
- SAM CLI - Install the SAM CLI
- Python 3 installed
- Docker - Install Docker community edition
To build and deploy your application for the first time, run the following in your shell:
sam build --use-container
sam deploy --guided
The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts:
- Stack Name: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name.
- AWS Region: The AWS region you want to deploy your app to.
- Confirm changes before deploy: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes.
- Allow SAM CLI IAM role creation: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the
CAPABILITY_IAM
value forcapabilities
must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass--capabilities CAPABILITY_IAM
to thesam deploy
command. - Save arguments to samconfig.toml: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run
sam deploy
without parameters to deploy changes to your application.
This project is developed and tested on Amazon Linux 2 using AWS Cloud9:
- Bash 4.2
- Python 3.8
- Python requirements listed in the requirements/requirements-build.txt and requirements/requirements-dev.txt files
- AWS SAM CLI ~= 1.24.0
- Docker >= 20
- GNU make >= 3.82
This project contains a Makefile that can be optionally used to facilitate tasks such as:
-
Create a python virtual environment and install the required dependencies:
make install
-
Build the project
make build
-
Deploy the stack:
Before deploying for the first time, you may need to configure your deployment settings using:
sam deploy --guided
Alternatively, you can edit the samconfig.toml file to configure your deployment values.
After that initial setup, you can deploy using:
make deploy
-
Run linters on the source code:
make lint
-
Publish to SAR:
make publish
-
Delete the stack:
make delete-stack
To invoke local functions with an event file:
make test-local-invoke
EVENT_FILE=tests/events/lex_v2_cfn_cr/create-bot.json make local-invoke-lex_v2_cfn_cr
To interactively debug inside the SAM container running a Lambda function put
debugpy
as a dependency in the requirements.txt
file under the function directory. That allows to attach a Python debugger to the Lambda function.
To debug using Visual Studio Code, create a launch task to attach to the debugger (example found in the launch.json file under the .vscode directory):
{
"name": "Debug SAM Lambda debugpy attach",
"type": "python",
"request": "attach",
"port": 5678,
"host": "localhost",
"pathMappings": [
{
"localRoot": "${workspaceFolder}/${relativeFileDirname}",
"remoteRoot": "/var/task"
}
],
}
Set the DEBUGGER
environmental variable. For example, to debug the
lex_v2_cfn_cr
function, run the following command (requires debugpy in the
function requirements.txt folder):
DEBUGGER=true EVENT_FILE=tests/events/lex_v2_cfn_cr/create-bot.json make local-invoke-lex_v2_cfn_cr
See the AWS SAM developer guide for an introduction to SAM specification, the SAM CLI, and serverless application concepts.
To delete this application, you can use the AWS CLI:
aws cloudformation delete-stack --stack-name '<cloudformation-stack-name>'
Or delete the stack using the AWS CloudFormation Console
See CONTRIBUTING for more information.
This project is licensed under the Apache-2.0 License.