Scripts
Scripts allow you to define custom commands that can be executed as part of your workflow. They can be used to perform a variety of tasks, such as building your application, running database migrations, or sending notifications.
- Scripts are used to specify and execute your custom scripts. Specifying a script in the Stacktape config can be beneficial for multiple reasons:
- scripts will be easily reusable by all members of your team,
- scripts can be executed automatically within lifecycle hooks (before/after deploy/delete etc.) or manually using script:run command,
- you can use
connectTo
property to easily inject environment variables needed for connecting to resources of your stack, - you can leverage bastion scripts and bastion tunneling to access resources which are only accessible within VPC.
- There are 3 types of scripts and based on the type of script there are differences on how the script is executed:
- local-script - script is executed locally (from the same host from which the stacktape command is being executed),
- local-script-with-bastion-tunneling - same as
local-script
, and additionally: Connections to selected resources listed in connectTo list are tunneled through bastion resource of your stack. This allows you to connect to resources (databases, redis-clusters...) which are only accessible within VPC from your local script (requires bastion resource), - bastion-script - script is executed on the bastion host (requires bastion resource).
- Scripts can specify either execute shell commands or scripts written in
Javascript
,Typescript
orPython
.
scripts:buildWeb:type: local-scriptproperties:executeCommand: npx gatsby buildhooks:beforeDeploy:- scriptName: buildWeb
Local script
A local script is executed on the same machine where the Stacktape command is run.
- The script must define one of the following properties:
executeCommand
,executeScript
,executeCommands
, orexecuteScripts
. - You can use the
connectTo
property to list the resources that your script needs to access. Stacktape will automatically inject the necessary environment variables for connecting to those resources. For more information, see Connecting to resources.
executeCommand
- Executes the specified command in a separate shell process. Uses
/bin/bash
on UNIX systems and default shell(usuallycmd.exe
) on Windows systems. - The command will be executed on the machine running the Stacktape command. If the command works on your machine, it doesn't mean it works for people or machines with different OSes or shells.
- Only one of
executeScript
,executeScripts
,executeCommand
orexecuteCommands
can be configured.
scripts:buildWeb:type: local-scriptproperties:executeCommand: npx gatsby build
executeScript
- The script can be written in Javascript, Typescript or Python.
- The script is executed in a separate process.
- The script is executed using an executable configured using
defaults:configure
command or a default executable on your machine:node
for Javascript and Typescriptpython
for Python
- Only one of
executeScript
,executeScripts
,executeCommand
orexecuteCommands
can be configured.
scripts:sendSlackNotification:type: local-scriptproperties:executeScript: scripts/send-slack-notification.ts
import { WebClient } from "@slack/web-api";const token = "my-access-token";const conversationId = "my-conversation-id";const slackClient = new WebClient(token);const errorData = JSON.parse(process.env.STP_ERROR);(async () => {await slackClient.chat.postMessage({channel: conversationId,text: errorData.message});})();
executeCommands
- Commands are executed in sequential order.
- Each command is executed in a separate shell process. Uses
/bin/bash
on UNIX systems and default shell(usuallycmd.exe
) on Windows systems. - Commands will be executed on the machine running the Stacktape command. If a command works on your machine, it doesn't mean it works for people or machines with different OSes or shells.
- Only one of
executeScript
,executeScripts
,executeCommand
orexecuteCommands
can be configured.
scripts:buildWeb:type: local-scriptproperties:executeCommands:- poetry run python manage.py makemigrations- poetry run python manage.py migrate
executeScripts
- Scripts are executed in sequential order.
- Script can be written in Javascript, Typescript or Python.
- Each script is executed in a separate process.
- Each script is executed using an executable configured using
defaults:configure
command or a default executable on your machine:node
for Javascript and Typescriptpython
for Python
- Only one of
executeScript
,executeScripts
,executeCommand
orexecuteCommands
can be configured.
scripts:sendSlackNotification:type: local-scriptproperties:executeScripts:- scripts/run-migration.ts- scripts/send-slack-notification.ts
Local script with bastion tunneling
A local script with bastion tunneling is executed in the same way as a regular local script, but connections to the resources listed in the connectTo
property are tunneled through a bastion server.
- This provides a secure, encrypted connection to your resources.
- It allows you to connect to resources that do not have a public endpoint and are only accessible within the stack's default VPC, such as a private
relational-database
orredis-cluster
. - The environment variables injected by the
connectTo
property are automatically adjusted to use the tunneled endpoints.
Your stack must have a bastion resource to use this type of script.
scripts:migrateDb:type: local-script-with-bastion-tunnelingproperties:executeScript: migrate.tsconnectTo:- myDatabasehooks:afterDeploy:- scriptName: migrateDbresources:myBastion:type: bastionmyDatabase:type: relational-databaseproperties:# database is only accessible from withing VPCaccessibility:accessibilityMode: vpcengine:type: postgresproperties:version: '16.2'primaryInstance:instanceSize: db.t3.microcredentials:masterUserPassword: my_secret_pass
import { DbClient } from './db';// using environment variable which was automatically injected thanks to connectTo property// injected environment variables are using tunneled endpointconst databaseConnectionString = process.env.STP_MY_DATABASE_CONNECTION_STRING;const client = new DbClient({ connectionString: databaseConnectionString });// perform migrations with the clientclient.close();
Bastion tunneling is supported for the following resource types:
relational-database
redis-cluster
application-load-balancer
private-service
(withloadBalancing.type
set toapplication-load-balancer
)
Bastion script
A bastion script is executed remotely on a bastion server.
- Logs from the script's execution are streamed in real-time to your local machine.
- This provides a unified way to execute a set of commands from anywhere.
- You can use the
connectTo
property to list the resources that your script needs to access. Stacktape will automatically inject the necessary environment variables for connecting to those resources. For more information, see Connecting to resources.
scripts:dbScript:type: bastion-scriptproperties:executeCommands:- psql $STP_MY_DATABASE_CONNECTION_STRING -c "SELECT 1 where 1=1"connectTo:- myDatabasehooks:afterDeploy:- scriptName: dbScriptresources:myBastion:type: bastionproperties:runCommandsAtLaunch:- yum update- yum install postgresql.x86_64 -ymyDatabase:type: relational-databaseproperties:accessibility:accessibilityMode: vpcengine:type: postgresproperties:version: '16.2'primaryInstance:instanceSize: db.t3.microcredentials:masterUserPassword: my_secret_pass
Connecting to resources
By referencing resources in connectTo
list, Stacktape automatically injects environment variables (containing information about resources in the list) into the script:
- names of environment variables use upper-snake-case and are in form STP_
[RESOURCE_NAME]
_[VARIABLE_NAME]
, - examples:
STP_MY_DATABASE_CONNECTION_STRING
orSTP_MY_EVENT_BUS_ARN
,
List of the injected environment variables depends on the resource type:
- Bucket:
NAME
,ARN
- DynamoDB table:
NAME
,ARN
,STREAM_ARN
- MongoDB Atlas cluster:
CONNECTION_STRING
- Relational(SQL) database:
CONNECTION_STRING
,JDBC_CONNECTION_STRING
,HOST
,PORT
(in case of aurora multi instance cluster additionally:READER_CONNECTION_STRING
,READER_JDBC_CONNECTION_STRING
,READER_HOST
) - Redis cluster:
HOST
,READER_HOST
,PORT
- Event bus:
ARN
- Function:
ARN
- Batch job:
JOB_DEFINITION_ARN
,STATE_MACHINE_ARN
- User auth pool:
ID
,CLIENT_ID
,ARN
- SNS Topic:
ARN
,NAME
- SQS Queue:
ARN
,NAME
,URL
- Upstash Kafka topic:
TOPIC_NAME
,TOPIC_ID
,USERNAME
,PASSWORD
,TCP_ENDPOINT
,REST_URL
- Upstash Redis:
HOST
,PORT
,PASSWORD
,REST_TOKEN
,REST_URL
,REDIS_URL
- Private service:
ADDRESS
- Web service:
URL
scripts:dbScript:type: local-scriptproperties:# The $STP_MY_DATABASE_CONNECTION_STRING environment variable is injected by connectToexecuteCommands:- psql $STP_MY_DATABASE_CONNECTION_STRING -c "SELECT * FROM users"connectTo:- myDatabaseresources:myDatabase:type: relational-databaseproperties:engine:type: postgresproperties:primaryInstance:instanceSize: db.t3.micro
If you are using a local-script-with-bastion-tunneling
script, connections to the resources listed in the connectTo
property are tunneled through a bastion host. This allows you to access resources that are only accessible from within the VPC and increases the security of the connection. For more information, see Local script with bastion tunneling.
How to execute a script
A script can be executed in two ways:
-
Using the
script:run
command:stacktape script:run --scriptName <<scriptName>> --stage <<stage>> -
Inside a hook.
Environment variables
Most commonly used types of environment variables:
- Static - string, number or boolean (will be stringified).
- Result of a custom directive.
- Referenced property of another resource (using $ResourceParam directive). To learn more, refer to referencing parameters guide. If you are using environment variables to inject information about resources into your script, see also property connectTo which simplifies this process.
- Value of a secret (using $Secret directive).
scripts:migrateDb:executeScript: scripts/migrate-db.tsenvironment:- name: DB_CONNECTION_STRINGvalue: $ResourceParam('mainDatabase', 'connectionString')resources:mainDatabase:type: relational-databaseproperties:credentials:masterUserPassword: my_secret_passwordengine:type: mysqlproperties:primaryInstance:instanceSize: db.t2.micro
Permissions
You can use the assumeRoleOfResource
property to grant a script the same AWS permissions as a specific resource.
- If specified, the script will be executed with the permissions of the specified resource.
- Resource must already be deployed when the script is executed.
- On the background, the script is injected with AWS environment variables which are automatically picked up by most of the AWS SDKs and CLIs.
- Supported resource types include:
function
batch-job
worker-service
web-service
private-service
multi-container-workload
nextjs-web
scripts:seedDb:executeScript: scripts/seed-db.tsassumeRoleOfResource: myFunctionenvironment:- name: TABLE_NAMEvalue: $ResourceParam('dynamoTable', 'name')resources:dynamoTable:type: dynamo-db-tablemyFunction:type: functionproperties:allowAccessTo:- dynamoTable