Custom Resources
Custom resources enable you to create resources with custom provisioning logic. This enables users to specify execution logic for resource creation, update, and deletion. This enables users to execute any kind of logic during stack deploy/delete. Moreover, it gives users the ability to provision any type of resource that is not included among Stacktape or Cloudformation resources. That way, users can manage all related resources in a single stack.
When to use
Common use cases for custom resources:
Provisioning non-AWS resources - While AWS offers huge amount of services and resources, in some cases, AWS might not offer a solution(resource) for your use-case, and often time a third-party solution better fits your needs. For example: using Auth0 over Cognito or using Algolia over AWS Elastisearch. These non-AWS resources can be provisioned using custom resources.
Performing provisioning steps not related to infrastructure - Deployment of infrastructure is only a part of having the application successfully running. You might need to seed the database or run migrations, both of which are a great fit for a custom resource. Another example might be running a smoke test from your custom resource to ensure that everything is running correctly after deployment.
Any other use case - Since you are fully in control of the code and therefore of what the custom resource does, there is virtually no limit of how to use custom resources. Custom resources can be powerful, but we advise users to be reasonable with them.
Usage
In Stacktape, custom resources are made of two parts:
custom-resource-definition - definition is special type of lambda function. It contains the custom logic - the code, which gets executed each time custom-resource-instance is created, updated, or deleted. To put into perspective of standard programming languages: custom-resource-definition is like a class and custom-resource-instance is instance of this class.
custom-resource-instance - when you specify instance, you must specify custom-resource-definition defintionName (which you want to instantiate) and resourceProperties(which can be thought of as arguments), which will be passed to the executing code.
All parts of a custom resource are shown in the following snippet. Individual parts are explained in the subsequent sections.
The following example shows a custom resource that is used to seed a mongo cluster.
resources:myMongoCluster:type: mongo-db-atlas-clusterproperties:clusterTier: M10mongoSeeder:type: custom-resource-definitionproperties:packageConfig:filePath: seed-the-mongo-cluster.tsaccessControl:allowAccessTo:- myMongoClusterseedMongoCluster:type: custom-resource-instanceproperties:definitionName: mongoSeederresourceProperties:mongoConnectionString: $Param('myMongoCluster', 'AtlasMongoCluster::SrvConnectionString')
Custom resource definition
Custom resource definition is similar to function definition. This is because on the background custom-resource-definition leverages lambda functions.
No description
Type: string "custom-resource-definition"
Configures the lambda function deployment package (lambda artifact) used for this custom resource
Type: LambdaPackageConfig
- Custom resource are managed using lambda functions.
- Lambda function is executed during custom resource events:
create
,update
anddelete
.
Environment variables injected to the batch job's environment
Type: Array of EnvironmentVar
- Environment variables are often used to inject information about other parts of the infrastrucutre (such as database URLs, secrets, etc.).
Runtime used to execute the custom resource lambda function
Type: string ENUM
Possible values: dotnetcore2.1go1.xjava11java8nodejs10.xnodejs12.xnodejs14.xnodejs8.10python2.7python3.6python3.7python3.8ruby2.5
- Stacktape automatically detects the function's language uses the latest runtime version associated with that language
- Example: uses
nodejs14.x
for all files ending with.js
and.ts
- You might want to use an older version if some of your dependencies are not not compatible with the default runtime version
Maximum amount of time (in seconds) the custom resource lambda function is allowed to run
Type: number
Maximum allowed time is 900 seconds.
Amount of memory (in MB) available to the function during execution
Type: number
- Must be between 128 MB and 10,240 MB in 1-MB increments.
- Amount of CPU power available to the function is also set using memory property - it's proportionate to the amount of available memory. Function with 1797MB has a CPU power equal to 1 virtual CPU. Lambda function can have a maximum of 6 vCPUs (at 10,240 MB of RAM).
Configures access to other resources of your stack (such as relational-databases, buckets, event-buses, etc.).
Type: AccessControl
Overrides one or more properties of the specified child resource.
Type: Object
- Child resouces are specified using their descriptive name (e.g.
DbInstance
orEvents.0.HttpApiRoute
). - To see all configurable child resources for given Stacktape resource, use
stacktape stack-info --detailed
command. - To see the list of properties that can be overriden, refer to AWS Cloudformation docs.
resources:myMongoCluster:type: mongo-db-atlas-clusterproperties:clusterTier: M10mongoSeeder:type: custom-resource-definitionproperties:packageConfig:filePath: seed-the-mongo-cluster.tsaccessControl:allowAccessTo:- myMongoClusterseedMongoCluster:type: custom-resource-instanceproperties:definitionName: mongoSeederresourceProperties:mongoConnectionString: $Param('myMongoCluster', 'AtlasMongoCluster::SrvConnectionString')
Code of custom resource
Package configuration allows you to specify a path to your code and other package properties. The code contains a logic of your custom resource.
Path to the entry point of your workload (relative to the stacktape config file)
Type: string
- Stacktape tries to bundle all your source code with its dependencies into a single file.
- If a certain dependency doesn't support static bundling (because it has binary, uses dynamic require() calls, etc.), Stacktape will install it copy it to the bundle
Configuration of packaging properties specific to given language
Exported function to use as the handler for you lambda function
Type: string
Files that should be explicitly included in the deployment package (glob pattern)
Type: Array of string
- Example glob pattern:
images/*.jpg
Files that should be explicitly excluded from deployment package (glob pattern)
Type: Array of string
Example glob pattern: images/*.jpg
Dependencies to ignore.
Type: Array of string
- These dependencies won't be a part of your deployment package.
resources:myMongoCluster:type: mongo-db-atlas-clusterproperties:clusterTier: M10mongoSeeder:type: custom-resource-definitionproperties:packageConfig:filePath: seed-the-mongo-cluster.tsaccessControl:allowAccessTo:- myMongoClusterseedMongoCluster:type: custom-resource-instanceproperties:definitionName: mongoSeederresourceProperties:mongoConnectionString: $Param('myMongoCluster', 'AtlasMongoCluster::SrvConnectionString')
Code example
The following example shows the code of our seeding custom resource in file seed-the-mongo-cluster.ts
See AWS documentation to learn more about:
- the type of requests (events) custom resource receives during stack operations
- response objects which you should return during respective operations
import mongoose from 'mongoose';import { SUCCESS, FAILED, send } from 'cfn-response-promise';// incoming event is in following form// {// "RequestType" : "Create" || "Update" || "Delete",// "RequestId" : "9db53695-b0a0-47d6-908a-ea2d8a3ab5d7",// "ResponseURL" : "https://...",// "ResourceType" : "AWS::Cloudformation::CustomResource",// "LogicalResourceId" : "...",// "StackId" : "arn:aws:cloudformation:...",// "ResourceProperties" : {// ... properties of custom-resource-instance// }// }export default async (event, context) => {// custom resource definition codelet success = true;let dataToReturn = {};try {// we are only seeding database if the operation is Createif (event.RequestType === 'Create') {// we are using the "mongoConnectionString" property passed by custom-resource-instance to create connectionconst connection = await mongoose.connect(event.ResourceProperties.mongoConnectionString, {authMechanism: 'MONGODB-AWS',authSource: '$external',useNewUrlParser: true,useUnifiedTopology: true,dbName: 'my-test-database'});// code with seeding the database ...// ...}} catch (err) {success = false;}await send(event, context, success ? SUCCESS : FAILED, dataToReturn, 'customresourceid');};// function must respond to "ResponseURL" with response in following form// we are using "cfn-response-promise" library which formats response for us// {// "Status" : "SUCCESS" || "FAILED",// "RequestId" : "9db53695-b0a0-47d6-908a-ea2d8a3ab5d7",// "LogicalResourceId" : "...",// "StackId" : "arn:aws:cloudformation:...",// "PhysicalResourceId" : "...",// "Data" : {// ... attributes which can be queried in template using $Param// }// }
Access control
Access control is configured same as access control of functions or other workloads.
Raw AWS IAM role statements appended to your resources's role.
Type: Array of StpIamRoleStatement
Names of the resources that will recieve basic permissions.
Type: Array of string
Granted permissions:
Bucket
- list objects in a bucket
- create / get / delete / tag object in a bucket
DynamoDb Table
- get / put / update / delete item in a table
- scan / query a table
- describe table stream
MongoDb Atlas Cluster
- Allows connection to a cluster with
accessibilityMode
set toscoping-workloads-in-vpc
. To learn more about MongoDb Atlas clusters accessibility modes, refer to MongoDB Atlas cluster docs.
Relational database
- Allows connection to a relational database with
accessibilityMode
set toscoping-workloads-in-vpc
. To learn more about relational database accessibility modes, refer to Relational databases docs.
Redis cluster
- Allows connection to a redis cluster with
accessibilityMode
set toscoping-workloads-in-vpc
. To learn more about redis cluster accessibility modes, refer to Redis clusters docs.
Event bus
- publish events to the specified Event bus
Function
- invoke the specified function
Batch job
- submit batch-job instance into batch-job queue
- list submitted job instances in a batch-job queue
- describe / terminate a batch-job instance
- list executions of state machine which executes the batch-job according to its strategy
- start / terminate execution of a state machine which executes the batch-job according to its strategy
In this example, we are granting access to the mongo cluster. This will inject credentials for access which are used in code.
resources:myMongoCluster:type: mongo-db-atlas-clusterproperties:clusterTier: M10mongoSeeder:type: custom-resource-definitionproperties:packageConfig:filePath: seed-the-mongo-cluster.tsaccessControl:allowAccessTo:- myMongoClusterseedMongoCluster:type: custom-resource-instanceproperties:definitionName: mongoSeederresourceProperties:mongoConnectionString: $Param('myMongoCluster', 'AtlasMongoCluster::SrvConnectionString')
No description
Type: UNSPECIFIED
Environment
Use environment variables for injecting information that resource needs during code execution.
Name of the environment variable
Type: string
Value of the environment variable
Type: (string or number or boolean)
Custom resource instance
Custom-resource-instance, creates instance of specified custom-resource-definition. Depending on the action (create/update/delete) stack is undergoing, the instance receives event (see code example) and executes the code.
resources:myMongoCluster:type: mongo-db-atlas-clusterproperties:clusterTier: M10mongoSeeder:type: custom-resource-definitionproperties:packageConfig:filePath: seed-the-mongo-cluster.tsaccessControl:allowAccessTo:- myMongoClusterseedMongoCluster:type: custom-resource-instanceproperties:definitionName: mongoSeederresourceProperties:mongoConnectionString: $Param('myMongoCluster', 'AtlasMongoCluster::SrvConnectionString')
No description
Type: string "custom-resource-instance"
Name of the custom-resource-definition
to use
Type: string
Properties passed to the custom resource instance
Type: Object
- These properties will be accessible to the custom resource lambda function during execution
Overrides one or more properties of the specified child resource.
Type: Object
- Child resouces are specified using their descriptive name (e.g.
DbInstance
orEvents.0.HttpApiRoute
). - To see all configurable child resources for given Stacktape resource, use
stacktape stack-info --detailed
command. - To see the list of properties that can be overriden, refer to AWS Cloudformation docs.
API reference
Path to tsconfig.json file to use.
Type: string
This is used mostly to resolve path aliases.
Emits decorator metadata to the final bundle.
Type: boolean
- This is used by frameworks like NestJS or ORMs like TypeORM.
- This is not turned on by default, because it can slow down the build process.
Dependencies to exclude from main bundle.
Type: Array of string
- These dependencies will be treated as
external
and won't be statically built into the main bundle - Instead, they will be installed and copied to the deployment package.
- Using
*
means all of the workload's dependencies will be treated as external