Directives
Directives are functions that can be used within a template. They are used to add dynamic behavior to the templates.
There are two types of directives:
- Built-in directives: built into Stacktape. Used for most common jobs (getting command-line arguments, formatting a string, etc.)
- Custom directives: user-defined directives (can be written in javascript, typescript or
python), specified in
directives
section of the template. Used to add custom logic (e.g. setting instance size based on a stage or fetching data required in configuration).
Using directives
Directive can be used for any value defined in the configuration. Directives always start with $
.
Directive can return:
- primite values - (strings, numbers or booleans)
- objects/arrays - accesing a property is done using a dot notation:
$Directive().propertyName
.
Stacktape directives
CliArgs
Returns arguments passed to the Stacktape command.
serviceName: cli-args-exampletags:- name: stagevalue: $CliArgs().stage
File
Reads and parses the content of a specified file.
Supported file types are:
DOTENV files
Returns the parsed contents of the specified .env
file.
myvar1="value1"
resources:myLambda:type: functionproperties:packageConfig:filePath: 'path/to/my-lambda.ts'environment:- name: MY_DIRECTIVE_VARIABLEvalue: $File('file.env').myvar1
INI files
Returns the parsed contents of the specified *.ini
file.
<<sectionName>>.<<variableName>>
myvar1=value1
resources:myLambda:type: functionproperties:packageConfig:filePath: 'path/to/my-lambda.ts'environment:- name: MY_DIRECTIVE_VARIABLEvalue: $File('file.ini').myvar1
JSON files
Returns the parsed contents of the specified *.json
file.
{ "myvar1": "value1" }
resources:myLambda:type: functionproperties:packageConfig:filePath: 'path/to/my-lambda.ts'environment:- name: MY_DIRECTIVE_VARIABLEvalue: $File('file.json').myvar1
YML files
Returns the parsed contents of the specified *.yml
file.
myvar1: value1
resources:myLambda:type: functionproperties:packageConfig:filePath: 'path/to/my-lambda.ts'environment:- 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 parameters 2-∞.
Format
directive cannot contain directives resolved at runtime as arguments. For these cases, refer to
directive CfFormat.
Examples:
- Directive
Format('{}-{}', 'foo', 'bar')
results infoo-bar
- Directive
Format('{}-mydomain.com', 'foo')
results infoo-mydomain.com
- Directive
Format('{}.{}', $Stage(), 'mydomain.com')
results in<<stage>>.mydomain.com
where<<stage>>
is result of the stage directive.
resources:myHttpApi:type: 'http-api-gateway'properties:domainNames:- domainName: $Format('{}-{}', $Stage(), 'mydomain.com')
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 directive. This can be used to allow multi-level nesting of directives. To learn more about directive nesting, refer to Nesting directives section.
variables:eventName: myCustomEventNameresources:# publishes events with EventName set to $Var().eventName into myEventBusmyPublisherFunction:type: 'function'properties:packageConfig:filePath: 'lambdas/event-bus-publisher.ts'environment:- name: EVENT_NAMEvalue: $Var().eventName...# listens for events with EventName set to $Var().eventName published into myEventBusmyConsumerFunction:type: 'function'properties:packageConfig:filePath: '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
stacktape configure-defaults
).
resources:myHttpApi:type: 'http-api-gateway'properties:domainNames:- domainName: $Format('{}-{}', $Stage(), 'mydomain.com')
Region
Returns region
.
Unlike using $CliArgs().region
, this directive also resolves default values (configured using
stacktape configure-defaults
).
Profile
Returns profile
.
Unlike using $CliArgs().profile
, this directive also resolves default values (configured using
stacktape configure-defaults
).
This
Returns the current stacktape template (as an object).
This enables yout to cross-reference any value directly from the template. Specific properties are accessed using dot notation.
serviceName: my-stackresources:myHttpApi:type: 'http-api-gateway'properties:domainNames:# we are interpolating stackName using This directive- domainName: $Format('{}-{}', $This().stackName, 'mydomain.com')
GitInfo
Returns the information from git.
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 |
serviceName: git-exampletags:- name: repositoryvalue: $GitInfo().repository
StackOutput
Returns output of another stack.
Can be used to reference parameters of resources deployed in a different stack.
- ARG1 - name of the stack that contains the output. Note that if the stack was deployed using Stacktape,
stackName
has the following form:<<stack-name-defined-in-config>>-<<stage>>
. - ARG2 - name of the referenced output
StackOutput
directive passes output by value. This is useful if the output value is to be used locally (for
example, in hooks).
When passing the output to stack resources (for example, via environment variables), we recommend using CfStackOutput directive, which passes output as a reference and brings some more guarantees (see CfStackOutput)
Consider we have deployed stack base-stack
with the following template to a dev
stage.
serviceName: base-stackoutputs:values:- name: baseBucketNamevalue: $Param('baseBucket', 'Bucket::Name')resources:baseBucket:type: bucket
In the following template of stack service-stack
, we reference the output of the previously deployed base-stack
.
serviceName: service-stackhooks:- triggers:- before:deployexecuteCommand: node validate-bucket-structure.jsenvironment:- name: BUCKET_NAMEvalue: $StackOutput('base-stack-dev', 'baseBucketName')resources:myFunction:type: functionproperties:...
Param
- Returns specified paremeter of the specified infrastructure resources. For example name or port of the database, URL of the HTTP API Gateway, etc.
- This directive is resolved at runtime. To understand directive resolution, refer to Resolving directives section.
- works with 2 types of resources:
- Stacktape resources - resource defined in
resources
section of the template - Cloudformation resources - resources defined in
cloudformationResources
section of the template file
- Stacktape resources - resource defined in
With Stacktape resources
- ARG1 - name of the referenced Stacktape resource
- ARG2 - specified the
sub-resource
and the referenced parameter. Must have the following form -<<descriptiveName>>::<<parameterName>>
:<<descriptiveName>>
- descritpive name of thesub-resource
(AWS Cloudformation resource). Stacktape resource specified inARG1
must contain this subresource.<<parameterName>>
- parameter of thesub-resource
to return
resources:myContainer:type: 'container-workload'properties:containers:- name: myContainerimageConfig:filePath: containers/ts-container.tsenvironment:- name: DB_URLvalue: $Param('smallPostgres', 'DbInstance::Endpoint.Address')...smallPostgres:type: 'relational-database'properties:...
With Cloudformation resources
- ARG1 - name of the AWS Cloudformation resource
- ARG2 - parameter of the AWS Cloudformation resource to return
cloudformationResources:MySnsTopic:type: AWS::SNS::Topicresources:processData:type: 'function'properties:packageConfig:filePath: 'lambdas/process.ts'destinations:onFailure: $Param('MySnsTopic', 'Arn')
Secret
Secret
directive interpolates secret which was stored in AWS secrets manager, for example, using
create secret command.
This directive is resolved at runtime. To understand directive resolution, see section Resolving directives.
ARG1 - secret name. If the stored secret is in JSON format, it is possible to extract the nested properties using dot notation.
Secret is never stored as plain text on a local device. Its value is interpolated only during runtime.
It is recommended to use secrets for storing database credentials or API keys used in infrastructure.
If the stored secret is in JSON format, it is possible to extract the nested properties using dot notation.
resources:myDatabase:type: 'relational-database'properties:credentials:masterUserName: master-user-123masterUserPassword: $Secret('my-master-pass')...
CfFormat
CfFormat
directive produces a string by formatting according to a specification.
This directive is resolved at runtime. To understand directive resolution, see section Resolving directives.
ARG1 - Specification is string containing format verbs. Format verbs are in a form
{}
.ARG2 - ARGX - values that will substitute the format verbs in specification. Amount of arguments must be equal to the number of format verbs used in the specification.
Compared to Format directive, the
CfFormat
directive can contain directives resolved at runtime as arguments.
Consider following examples:
- Directive
CfFormat('{}-{}', 'foo', 'bar')
results infoo-bar
- Directive
CfFormat('{}-mydomain.com', 'foo')
results infoo-mydomain.com
It is possible to use other directives within the CfFormat
directive:
resources:myLambda:type: functionproperties:packageConfig:filePath: 'path/to/my-lambda.ts'environment:- name: DATABASE_URL_STRINGvalue: $CfFormat('{}:{}/app', $Param('myDatabase', 'DbInstance::Endpoint.Address'), $Param('myDatabase', 'DbInstance::Endpoint.Port'))myDatabase:type: 'relational-database'properties:credentials:masterUserName: user123masterUserPassword: $Secret('my-secret-pass')...
CfStackOutput
CfStackOutput
directive interpolates output of another stack. This enables users to pass values such as database URLs
or event bus names from one stack to another, hence allowing users to connect multiple stacks.
This directive is resolved at runtime. To understand directive resolution, see section Resolving directives.
- ARG1 - Full stack name - name of your stack which contains the output. Name is in form
<<stack-name>>-<<stage>>
. - ARG2 - Name of the output you are referencing.
CfStackOutput
directive passes output by reference. This ensures that:
- the stack which contains the referenced output does not get deleted,
- the referenced output on the referenced stack does not change.
In some cases, it is necessary to resolve the output value locally. In those cases, use StackOutput directive.
Consider we have deployed stack base-stack
with the following template to a dev
stage.
serviceName: base-stackoutputs:values:- name: baseBucketNamevalue: $Param('baseBucket', 'Bucket::Name')resources:baseBucket:type: bucket
In the following template, we reference the output of the previously deployed base-stack
in a function's environment
variable.
serviceName: service-stackresources:myFunction:type: functionproperties:packageConfig:filePath: 'path/to/my-lambda.ts'environment:- name: BASE_BUCKET_NAMEvalue: $CfStackOutput('base-stack-dev', 'baseBucketName')
Custom directives
Besides the Stacktape directives, users can create their own directives.
Custom directives are typescript
or javascript
or python
functions which can return simple values such as
string or number or a complex object. If the returned value is a complex object, nested value can be retrieved using dot
notation.
All of the custom directives are resolved locally. To understand directive resolution, see section Resolving directives.
Using custom directives includes two steps:
- User first "registers" a directive in the
directives
section of the template, - The directive can then be used within a template as any Stacktape directive.
Name of the directive
Name of the directive.
Type: string
Path to the file where directive is defined. Format: {file-path}:{function-name}
Path to the file where directive is defined.
Type: string
- Format:
{file-path}:{handler}
- If you do not specify
{handler}
part:- for
.js
and.ts
files,default
export is used - for
.py
files,main
functions is used
- for
Custom typescript directive
Consider following typescript file my-directive.ts
export const decideValueFromStage = (stageName: string) => {if (stageName === 'staging') {return 'my-staging-value';}return 'my-other-value';};
We can use the function decideValueFromStage
as a directive in our template following way
directives:- name: DecideValuefilePath: my-directive.ts:decideValueFromStageresources:myLambda:type: functionproperties:packageConfig:filePath: 'path/to/my-lambda.ts'environment:- name: MY_DIRECTIVE_VARIABLEvalue: $DecideValue($Stage())
Custom javascript directive
Consider following javascript file my-directive.js
export const getDate = () => {const date = new Date();return {isoString: date.toISOString(),utcString: date.toUTCString()};};
We can use the function getDate
as a directive in our template following way
directives:- name: GetDatefilePath: user-defined.js:getDateresources:myLambda:type: functionproperties:packageConfig:filePath: 'path/to/my-lambda.ts'environment:- name: MY_DIRECTIVE_VARIABLEvalue: $GetDate().isoString
Custom python directive
Consider following python file my-directive.py
def get_cluster_tier(stage):if (stage == 'staging'):return 'M5'return 'M2'
We can use the function get_cluster_tier
as a directive in our template following way
directives:- name: GetMongoTierfilePath: my-directive.py:get_cluster_tierresources:myMongoCluster:type: mongo-db-atlas-clusterproperties:clusterTier: $GetMongoTier($Stage())
Resolving directives
Each directive is either resolved locally or at runtime:
locally - directive is fully resolved before deployment begins. In other words, the output value of the directive is put into the Cloudformation template (used during deployment) fully resolved in its final form.
runtime - directive is resolved only partially before deployment begins. Instead, a reference is put into the Cloudformation template (used during deployment), which will get resolved during the deployment.
For example, in the case of Param directive, we are unable to know the parameter of the resource before deployment. Instead, the resource which is in the scope of the
Param
directive must be deployed first, and only after that the directive is fully resolved and the parameter can be used. This happens automatically during the deployment process
Nesting directives
It is possible to nest directives. Nesting happens when the result of one directive is passed as an argument to another directive.
There are two limitations to nesting directives:
Result of a directive resolved at runtime cannot be passed as an argument to a directive resolved locally. This is due to the nature of different resolution types. To understand directive resolution, see section Resolving directives.
Maximum nesting depth within a template is 1. However, this limitation can be overcome by using variables in the
variables
section to store the intermediate result.See the following example where we:
- first, resolve the name of the file based on the stage using a custom
$GetFileName
directive and store it in theenvFileName
variable - second, use the
envFileName
in the$File
directive to read the contents of the file
- first, resolve the name of the file based on the stage using a custom
export const getFileNameFromStage = (stageName: string) => {if (stageName === 'staging') {return 'my-staging-vars.env';}return 'my-dev-vars.env';};
directives:- name: GetFileNamefilePath: my-directive.ts:getFileNameFromStagevariables:envFileName: $GetFileName($Stage())resources:myLambda:type: functionproperties:packageConfig:filePath: 'path/to/my-lambda.ts'environment:- name: MY_DIRECTIVE_VARIABLEvalue: $File($Var().envFileName).myvar1