logoStacktape docs




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:

  1. Built-in directives: built into Stacktape. Used for most common jobs (getting command-line arguments, formatting a string, etc.)
  2. 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-example
tags:
- name: stage
value: $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: function
properties:
packageConfig:
filePath: 'path/to/my-lambda.ts'
environment:
- name: MY_DIRECTIVE_VARIABLE
value: $File('file.env').myvar1

INI files

Returns the parsed contents of the specified *.ini file.

<<sectionName>>.<<variableName>>

myvar1=value1
resources:
myLambda:
type: function
properties:
packageConfig:
filePath: 'path/to/my-lambda.ts'
environment:
- name: MY_DIRECTIVE_VARIABLE
value: $File('file.ini').myvar1

JSON files

Returns the parsed contents of the specified *.json file.

{ "myvar1": "value1" }
resources:
myLambda:
type: function
properties:
packageConfig:
filePath: 'path/to/my-lambda.ts'
environment:
- name: MY_DIRECTIVE_VARIABLE
value: $File('file.json').myvar1

YML files

Returns the parsed contents of the specified *.yml file.

myvar1: value1
resources:
myLambda:
type: function
properties:
packageConfig:
filePath: 'path/to/my-lambda.ts'
environment:
- name: MY_DIRECTIVE_VARIABLE
value: $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 in foo-bar
  • Directive Format('{}-mydomain.com', 'foo') results in foo-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: myCustomEventName
resources:
# publishes events with EventName set to $Var().eventName into myEventBus
myPublisherFunction:
type: 'function'
properties:
packageConfig:
filePath: 'lambdas/event-bus-publisher.ts'
environment:
- name: EVENT_NAME
value: $Var().eventName
...
# listens for events with EventName set to $Var().eventName published into myEventBus
myConsumerFunction:
type: 'function'
properties:
packageConfig:
filePath: 'lambdas/consumer.ts'
events:
- type: event-bus
properties:
eventBusName: myEventBus
eventPattern:
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-stack
resources:
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 usageDescription
$GitInfo().sha1Return SHA-1 of the latest commit
$GitInfo().commitReturn the latest commit ID
$GitInfo().branchReturns the name of the current branch
$GitInfo().messageReturns the message of the last commit
$GitInfo().userReturns git user's name
$GitInfo().emailReturns git user's email
$GitInfo().repositoryReturns the name of the git repository
$GitInfo().tagsReturns the tags pointing to the current commit
$GitInfo().describeReturn the most recent tag that is reachable from a commit

serviceName: git-example
tags:
- name: repository
value: $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-stack
outputs:
values:
- name: baseBucketName
value: $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-stack
hooks:
- triggers:
- before:deploy
executeCommand: node validate-bucket-structure.js
environment:
- name: BUCKET_NAME
value: $StackOutput('base-stack-dev', 'baseBucketName')
resources:
myFunction:
type: function
properties:
...

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:

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 the sub-resource (AWS Cloudformation resource). Stacktape resource specified in ARG1 must contain this subresource.
    • <<parameterName>> - parameter of the sub-resource to return

resources:
myContainer:
type: 'container-workload'
properties:
containers:
- name: myContainer
imageConfig:
filePath: containers/ts-container.ts
environment:
- name: DB_URL
value: $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::Topic
resources:
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-123
masterUserPassword: $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 in foo-bar
  • Directive CfFormat('{}-mydomain.com', 'foo') results in foo-mydomain.com

It is possible to use other directives within the CfFormat directive:

resources:
myLambda:
type: function
properties:
packageConfig:
filePath: 'path/to/my-lambda.ts'
environment:
- name: DATABASE_URL_STRING
value: $CfFormat('{}:{}/app', $Param('myDatabase', 'DbInstance::Endpoint.Address'), $Param('myDatabase', 'DbInstance::Endpoint.Port'))
myDatabase:
type: 'relational-database'
properties:
credentials:
masterUserName: user123
masterUserPassword: $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-stack
outputs:
values:
- name: baseBucketName
value: $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-stack
resources:
myFunction:
type: function
properties:
packageConfig:
filePath: 'path/to/my-lambda.ts'
environment:
- name: BASE_BUCKET_NAME
value: $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:

  1. User first "registers" a directive in the directives section of the template,
  2. The directive can then be used within a template as any Stacktape directive.
DirectiveDefinition  API reference
name
Required

Name of the directive

Name of the directive.

Type: string

filePath
Required

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


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: DecideValue
filePath: my-directive.ts:decideValueFromStage
resources:
myLambda:
type: function
properties:
packageConfig:
filePath: 'path/to/my-lambda.ts'
environment:
- name: MY_DIRECTIVE_VARIABLE
value: $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: GetDate
filePath: user-defined.js:getDate
resources:
myLambda:
type: function
properties:
packageConfig:
filePath: 'path/to/my-lambda.ts'
environment:
- name: MY_DIRECTIVE_VARIABLE
value: $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: GetMongoTier
filePath: my-directive.py:get_cluster_tier
resources:
myMongoCluster:
type: mongo-db-atlas-cluster
properties:
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:

  1. 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.

  2. 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 the envFileName variable
    • second, use the envFileName in the $File directive to read the contents of the file

export const getFileNameFromStage = (stageName: string) => {
if (stageName === 'staging') {
return 'my-staging-vars.env';
}
return 'my-dev-vars.env';
};

directives:
- name: GetFileName
filePath: my-directive.ts:getFileNameFromStage
variables:
envFileName: $GetFileName($Stage())
resources:
myLambda:
type: function
properties:
packageConfig:
filePath: 'path/to/my-lambda.ts'
environment:
- name: MY_DIRECTIVE_VARIABLE
value: $File($Var().envFileName).myvar1