Scripts
Introduction
- 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
.
Copy
scripts:buildWeb:type: local-scriptproperties:executeCommand: npx gatsby buildhooks:beforeDeploy:- scriptName: buildWeb
Local script
Local script is executed locally (from the same host from which the stacktape command is being executed):
- The script must define one of
executeCommand
,executeScript
,executeCommands
orexecuteScripts
properties. - Use
connectTo
property for listing resources of your stack which you will be accessing from your script. Stacktape will then automatically inject environment variables needed for connecting to those resources into your script. For more details, see section Using connectTo.
Using 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.
Copy
scripts:buildWeb:type: local-scriptproperties:executeCommand: npx gatsby build
Using 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.
Copy
scripts:sendSlackNotification:type: local-scriptproperties:executeScript: scripts/send-slack-notification.ts
Copy
import { WebClient } from "@slack/web-api";// An access token (from your Slack app or custom integration - xoxp, xoxb)const token = "my-access-token";// This argument can be a channel ID, a DM ID, a MPDM ID, or a group IDconst 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});})();
Using 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.
Copy
scripts:buildWeb:type: local-scriptproperties:executeCommands:- poetry run python manage.py makemigrations- poetry run python manage.py migrate
Using 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.
Copy
scripts:sendSlackNotification:type: local-scriptproperties:executeScripts:- scripts/run-migration.ts- scripts/send-slack-notification.ts
Local script with bastion tunneling
Local script with bastion tunneling executes in the same way as local script.
In addition, when using local script with bastion tunneling, connections to selected resources listed in connectTo list, are tunneled through bastion server:
- When using tunneled connection, you are using secured encrypted connection running through the bastion server of your stack (instead of connecting to the resource directly over the internet).
- Tunneled connection allows you to connect to resources which do not have public endpoint and are only accessible within stack's default VPC such as private relational-database or redis-cluster from your local host (where script is executed).
- To use the tunneled endpoint of the resource (instead of using direct endpoint) in your script/command, use environment variables injected by connectTo property. These environment variables are automatically adjusted to use the tunneled endpoints.
Your stack must contain bastion resource to use this type of script.
Example script with tunneling
Copy
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
Stacktape config using the migration script with tunneling
Copy
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();
Example pseudo migration script
Bastion tunneling is supported for following resource types:
relational-database
redis-cluster
application-load-balancer
private-service
(with loadBalancing type application-load-balancer)
Bastion script
Bastion script is executed remotely on bastion server:
- Logs from the script execution are fetched real-time and printed to your local host.
- Executing commands directly on bastion server gives you unified way to execute set of commands from anywhere.
- Use
connectTo
property for listing resources of your stack which you will be accessing from your commands. Stacktape will then automatically inject environment variables needed for connecting to those resources into your script. For more details, see section Using connectTo.
Example bastion script
Copy
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
Example bastion script executing commands on database
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
Copy
scripts:dbScript:type: local-scriptproperties:# environment variable $STP_MY_DATABASE_CONNECTION_STRING is injected thanks to 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
Example config using script with connectTo
If you are using local-script-with-bastion-tunneling
script, connections to selected resources listed in connectTo
are tunneled through bastion host. This allows for accessing resources, which are only accessible from within the VPC
and increases security of connection. Refer to
bastion tunneling docs for more
information.
Executing script
The script can be executed in 2 ways:
using script:run command
Copy
stacktape script:run --scriptName <<scriptName>> --stage <<stage>>inside a hook
Environment
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).
Copy
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