Directives
Introduction
YAML is a configuration language. It's declarative, clear, concise and brief. We believe using YAML is the best way to write configurations. However, being a configuration language, it doesn't allow you to include dynamic behavior. This is why Stacktape supports directives
Directives are functions that can be used within a template. They can be used to add dynamic behavior to the templates.
Stacktape supports 2 types of directives:
- Built-in directives: Built into Stacktape. Used for the most common jobs (e.g. getting command-line arguments, formatting a string)
- Custom directives: User-defined directives. Used to add custom logic (e.g. setting database instance size based on a stage or fetching data required in configuration). Custom directives can be written in Javascript, Typescript or Python.
Using directives
Directives always start with
$
.Directive can be used to configure any property defined in the configuration.
Copy
myProperty: $MyDirective()Directive can return:
- primitive values - strings, numbers or booleans.
- objects and arrays - Accessing a property is done using a dot notation:
$Directive().propertyName
.
Directive can accept any number of arguments.
- If you are passing arguments in-line, these arguments MUST be primitive values (not objects).
- If you pass arguments as a result of another directives, these arguments can be primitive values, objects or arrays.
Copy
myProperty: $MyDirective('myParameter', 3, true)Directives can be nested. However, there are 2 limitations:
- Result of a directive resolved at runtime cannot be passed as an argument to a directive resolved locally.
- Maximum nesting depth within a template is 2.
$MyDirective1($MyDirective2())
is valid.$MyDirective1($MyDirective2($MyDirective2()))
is not. To overcome this limitation, you can save the output of a directives to a variable, in thevariables
section of your configuration.
Copy
myProperty: $MyDirective1($MyDirective2())
Built-in directives
- Used for the most common jobs, e.g. getting command-line arguments, formatting a string, etc.
- Built-in directives can be resolved in 2 ways: locally or at runtime.
Local directives
- The directive is completely resolved when the configuration is loaded. The directive body is substituted with the value returned from the directive.
$CliArgs()
- Returns command-line arguments passed to the Stacktape command.
Copy
stackConfig:tags:- name: stagevalue: $CliArgs().stage
$File()
dotenv files
- Returns the parsed contents of the specified
.env.*
(dotenv) file.
Copy
myvar1=value1
Copy
resources:myFunction:type: functionproperties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: path/to/my-lambda.tsenvironment:- name: MY_DIRECTIVE_VARIABLEvalue: $File('.env.staging').myvar1
ini files
- Returns the parsed contents of the specified
*.ini
file.
Copy
myvar1=value1
Copy
resources:myFunction:type: functionproperties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: path/to/my-lambda.tsenvironment:- name: MY_DIRECTIVE_VARIABLEvalue: $File('file.ini').myvar1
JSON files
- Returns the parsed contents of the specified
*.json
file.
Copy
{ "myvar1": "value1" }
Copy
resources:myFunction:type: functionproperties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: path/to/my-lambda.tsenvironment:- name: MY_DIRECTIVE_VARIABLEvalue: $File('file.json').myvar1
YML files
- Returns the parsed contents of the specified
*.yml
file.
Copy
myvar1: value1
Copy
resources:myFunction:type: functionproperties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: path/to/my-lambda.tsenvironment:- name: MY_DIRECTIVE_VARIABLEvalue: $File('file.yml').myvar1
$Format()
Returns an interpolated string.
First argument is a string to be interpolated. Every
{}
sub-string in this string will be substituted by the values passed as arguments 2-∞. There must be the same amount of{}
as the number of arguments 2-∞.$Format()
directive cannot contain directives resolved at runtime as arguments. For these use-cases, use the $CfFormat().Examples:
- Directive
$Format('{}-{}', 'foo', 'bar')
will result infoo-bar
- Directive
$Format('{}-mydomain.com', 'foo')
will result infoo-mydomain.com
- Directive
$Format('{}.{}', $Stage(), 'mydomain.com')
will result instaging.mydomain.com
given thestage
is set tostaging
.
- Directive
$Var()
Returns variable specified in the
variables
section.Variables are used to:
- reference values that are used more than once in the template
- better organize your template files
- save intermediate return values of other directives. This can be used to allow multi-level nesting of directives.
Copy
variables:eventName: myCustomEventNameresources:myEventBus:type: 'event-bus'# publishes events with EventName set to $Var().eventName into myEventBusmyPublisherFunction:type: 'function'properties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: 'lambdas/event-bus-publisher.ts'environment:- name: EVENT_NAMEvalue: $Var().eventNameconnectTo:- myEventBus# listens for events with EventName set to $Var().eventName published into myEventBusmyConsumerFunction:type: 'function'properties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: 'lambdas/consumer.ts'events:- type: event-busproperties:eventBusName: myEventBuseventPattern:detail:EventName:- $Var().eventName
$Stage()
- Returns
stage
. - Unlike using
$CliArgs().stage
, this directive also resolves default values (configured using defaults:configure command).
$Region()
- Returns
region
. - Unlike using
$CliArgs().region
, this directive also resolves default values (configured using defaults:configure command).
$Profile()
- Returns
profile
. - Unlike using
$CliArgs().profile
, this directive also resolves default values (configured using defaults:configure command).
$This()
- Returns the current stacktape template as an object.
Copy
resources:myHttpApi:type: 'http-api-gateway'properties:customDomains:# we are interpolating serviceName using This directive- domainName: $Format('{}-{}', $This().serviceName, 'mydomain.com')
$GitInfo()
- Returns the information about the current git repository, git user, etc.
Directive usage | Description |
---|---|
$GitInfo().sha1 | Return SHA-1 of the latest commit |
$GitInfo().commit | Return the latest commit ID |
$GitInfo().branch | Returns the name of the current branch |
$GitInfo().message | Returns the message of the last commit |
$GitInfo().user | Returns git user's name |
$GitInfo().email | Returns git user's email |
$GitInfo().repository | Returns the name of the git repository |
$GitInfo().tags | Returns the tags pointing to the current commit |
$GitInfo().describe | Return the most recent tag that is reachable from a commit |
Copy
stackConfig:tags:- name: stagevalue: $GitInfo().repository
$StackOutput()
- Returns the specified output of another stack.
- Used to reference parameters of resources deployed in a different stack.
- Arguments
- stack name - name of the stack that contains the output. Note that if the stack was deployed using Stacktape,
stackName
has the following format:<<projectName>>-<<stage>>
. - output name - name of the output to return.
- stack name - name of the stack that contains the output. Note that if the stack was deployed using Stacktape,
$StackOutput()
directive returns the output value of another stack when the current stack is being deployed.
To ensure the value won't change, or that the other stack won't get deleted, use the $CfStackOutput() directive
Consider we have deployed stack base-stack
with the following configuration to a dev
stage.
Copy
stackConfig:outputs:- name: bucketNamevalue: $ResourceParam('baseBucket', 'arn')resources:baseBucket:type: bucket
We can now reference output of the base-stack
in another stack:
Copy
variables:baseStackName: $Format('{}-{}', 'base-stack', $Stage())scripts:validateBucket:executeScript: hooks/validate-bucket-in-base-stack.tsenvironment:- name: BUCKET_NAMEvalue: $StackOutput($Var().baseStackName, 'baseBucketName')hooks:beforeDeploy:- executeNamedScript: validateBucketresources: ...
Runtime directives
- Some directives are not resolved immediately (locally by Stacktape).
- Example: To pass a connectionString of your database to an environment variable of your container, you can use
$ResourceParam('myDatabase', 'connectionString')
directive. The connection string is known only after the database has been created, and therefore can't be resolved before the first-time deployment. Instead, the resolution of the directive is handled by AWS CloudFormation during the deployment. Under the hood, the directives are transformed into CloudFormation intrinsic functions. - For convenience, when using runtime directives in post deploy hooks or when running dev command, the results of runtime directives will be automatically downloaded and resolved as local directives.
Runtime directives can only be used in the resources
and scripts
sections of the Stacktape configuration file.
- For convenience, Stacktape resolves runtime directives locally (the value is automatically downloaded) when
used inside a script or when using development commands (
cw:run-local
andfn:develop
).
$ResourceParam()
- Returns specified parameter of a specified Stacktape resource. For example name or port of the database, URL of the HTTP API Gateway, etc.
- Arguments:
- 1. stacktape resource name - name of the referenced Stacktape resource as specified in the configuration.
- 2. parameter name - parameter to reference. You can find a list of all referenceable parameters for every resource in its docs:
- To learn more about referencing parameters of your infrastructure resources, refer to Referencing parameters.
Copy
resources:myDatabase:type: relational-databaseproperties: ...database properties...myFunction:type: functionproperties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: path/to/my/lambda-requiring-db.tsenvironment:- name: DB_CONNECTION_STRINGvalue: $ResourceParam('myDatabase', 'connectionString')
Example usage of $ResourceParam() directive.
$CfResourceParam()
- Returns specified parameter of a specified Cloudformation resource. For example name or port of the database, URL of the HTTP API Gateway, etc.
- Arguments:
- 1. cloudformation logical name - name of the AWS Cloudformation resource.
- If you want to reference a resource defined in
cloudformationResources
section, just use its name. - If you want to reference a child resources of a Stacktape resource, you can get a list of child resource using stack-info command
- If you want to reference a resource defined in
- 2. parameter name - parameter of the AWS Cloudformation resource to reference. To see a list of all referenceable cloudformation parameters, refer to Referenceable parameters docs
- 1. cloudformation logical name - name of the AWS Cloudformation resource.
- To learn more about referencing parameters of your infrastructure resources, refer to Referencing parameters.
Copy
cloudformationResources:MySnsTopic:Type: AWS::SNS::Topicresources:myBucket:type: bucketprocessData:type: functionproperties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: path/to/my/lambda.tsdestinations:onFailure: $CfResourceParam('MySnsTopic', 'Arn')environment:- name: BUCKET_NAMEvalue: $CfResourceParam('MyBucketBucket', 'Name')
Example usage of $CfResourceParam() directive.
$Secret()
- Returns the value of specified secret. To learn more about secrets, refer to secrets docs.
- Arguments:
- 1. secret name - Name of the secret. If the stored secret is in JSON format, you can extract the nested properties using the dot notation,
Copy
resources:myDatabase:type: relational-databaseproperties:credentials:masterUserPassword: $Secret('my-database-password')...more properties...
or
Copy
resources:myDatabase:type: relational-databaseproperties:credentials:masterUserPassword: $Secret('my-database-credentials.password')...more properties...
$CfFormat()
Returns an interpolated string.
Compared to $Format() directive, the
$CfFormat()
directive can contain directives resolved at runtime as arguments.Arguments:
- string to interpolate - Occurrences of
{}
will be replaced by latter arguments. - (arguments 2 to infinity) value to use in the interpolation - The amount of arguments must be equal to the
number of
{}
used in the first argument.
- string to interpolate - Occurrences of
Examples:
- Directive
CfFormat('{}-{}', 'foo', 'bar')
will result infoo-bar
- Directive
CfFormat('{}-mydomain.com', 'foo')
will result infoo-mydomain.com
- Directive
CfFormat('{}.mydomain.com', $Stage())
will result instaging.mydomain.com
given thestage
is set tostaging
.
- Directive
$CfStackOutput()
Returns the output of another stack. This allows you to reference resources deployed in another stack.
The stack you're referencing must be already deployed.
If you try to delete a stack that has a stack output referenced by another stack, you'll get an error.
If you want to get the output locally (download it and pass it as value), use the $StackOutput() directive.
Arguments:
- stack name - name of the stack that contains the output. Note that if the stack was deployed using Stacktape,
stackName
has the following form:<<projectName>>-<<stage>>
. - output name - name of the output to reference.
- stack name - name of the stack that contains the output. Note that if the stack was deployed using Stacktape,
Consider we have deployed stack base-stack
with the following configuration to a dev
stage.
Copy
stackConfig:outputs:- name: bucketNamevalue: $ResourceParam('baseBucket', 'arn')resources:baseBucket:type: bucket
We can now reference output of the base-stack
in another stack:
Copy
variables:baseStackName: $Format('{}-{}', 'base-stack', $Stage())resources:myFunction:type: functionproperties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: path/to/my/lambda-requiring-bucket-name.tsenvironment:- name: OTHER_STACK_BUCKET_NAMEvalue: $CfStackOutput($Var().baseStackName, 'bucketName')
Custom directives
- User-defined directives.
- Used to add custom logic (e.g. setting database instance size based on a stage or fetching data required in configuration).
Registering directives
- To use a directive, you first need to register it in the
directives
section of your configuration file. - You can configure the function to use as your directive using the
:
. If you don't specify the function name,- for javascript and typescript directives: the
default
export is used - for python directives: the
main
function is used
- for javascript and typescript directives: the
Copy
directives:- name: myDirectivefilePath: path/to/my/directive.ts:functionName
Writing directives
- Custom directives can be written in Javascript, Typescript or Python.
- Custom directives can return primitive values, objects or arrays. If the returned value is an object, you can access
it using the dot notation:
$GetBooks().books.Dune
.
In Javascript and Typescript
- You can write directives using Javascript (ES2020) and Typescript. The code will be automatically transpiled.
- Your directive can return a promise - it will be automatically awaited.
- Any code OUTSIDE the function handler will be executed only once, when the configuration is parsed for the first time.
Copy
export const getDbInstanceSize = (stage: string) => {if (stage === "production") {return "db.m5.xlarge";}return "db.t2.micro";};
Copy
directives:- name: getDbInstanceSizefilePath: my-directive.ts:getDbInstanceSizeresources:myDatabase:type: relational-databaseproperties:credentials:masterUserPassword: $Secret('database.password')engine:type: postgresproperties:version: '16.2'port: 5432primaryInstance:instanceSize: $getDbInstanceSize($Stage())
In Python
- Any code OUTSIDE the function handler will be executed only once, when the configuration is parsed for the first time.
Copy
def get_db_instance_size(stage):if (stage == 'production'):return 'M5'return 'M2'
Copy
directives:- name: get_db_instance_sizefilePath: my-directive.py:get_db_instance_sizeresources:myDatabase:type: relational-databaseproperties:credentials:masterUserPassword: $Secret('database.password')engine:type: postgresproperties:version: '16.2'port: 5432primaryInstance:instanceSize: $get_db_instance_size($Stage())