Stacktape
Stacktape


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:
    1. local-script - script is executed locally (from the same host from which the stacktape command is being executed),
    2. 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),
    3. 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 or Python.
scripts:
buildWeb:
type: local-script
properties:
executeCommand: npx gatsby build
hooks:
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, or executeScripts.
  • 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(usually cmd.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 or executeCommands can be configured.
scripts:
buildWeb:
type: local-script
properties:
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 Typescript
    • python for Python
  • Only one of executeScript, executeScripts, executeCommand or executeCommands can be configured.
scripts:
sendSlackNotification:
type: local-script
properties:
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(usually cmd.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 or executeCommands can be configured.
scripts:
buildWeb:
type: local-script
properties:
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 Typescript
    • python for Python
  • Only one of executeScript, executeScripts, executeCommand or executeCommands can be configured.
scripts:
sendSlackNotification:
type: local-script
properties:
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 or redis-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-tunneling
properties:
executeScript: migrate.ts
connectTo:
- myDatabase
hooks:
afterDeploy:
- scriptName: migrateDb
resources:
myBastion:
type: bastion
myDatabase:
type: relational-database
properties:
# database is only accessible from withing VPC
accessibility:
accessibilityMode: vpc
engine:
type: postgres
properties:
version: '16.2'
primaryInstance:
instanceSize: db.t3.micro
credentials:
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 endpoint
const databaseConnectionString = process.env.STP_MY_DATABASE_CONNECTION_STRING;
const client = new DbClient({ connectionString: databaseConnectionString });
// perform migrations with the client
client.close();

Graphical overview of tunneling

Bastion tunneling is supported for the following resource types:

  • relational-database
  • redis-cluster
  • application-load-balancer
  • private-service (with loadBalancing.type set to application-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-script
properties:
executeCommands:
- psql $STP_MY_DATABASE_CONNECTION_STRING -c "SELECT 1 where 1=1"
connectTo:
- myDatabase
hooks:
afterDeploy:
- scriptName: dbScript
resources:
myBastion:
type: bastion
properties:
runCommandsAtLaunch:
- yum update
- yum install postgresql.x86_64 -y
myDatabase:
type: relational-database
properties:
accessibility:
accessibilityMode: vpc
engine:
type: postgres
properties:
version: '16.2'
primaryInstance:
instanceSize: db.t3.micro
credentials:
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 or STP_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-script
properties:
# The $STP_MY_DATABASE_CONNECTION_STRING environment variable is injected by connectTo
executeCommands:
- psql $STP_MY_DATABASE_CONNECTION_STRING -c "SELECT * FROM users"
connectTo:
- myDatabase
resources:
myDatabase:
type: relational-database
properties:
engine:
type: postgres
properties:
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.ts
environment:
- name: DB_CONNECTION_STRING
value: $ResourceParam('mainDatabase', 'connectionString')
resources:
mainDatabase:
type: relational-database
properties:
credentials:
masterUserPassword: my_secret_password
engine:
type: mysql
properties:
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.ts
assumeRoleOfResource: myFunction
environment:
- name: TABLE_NAME
value: $ResourceParam('dynamoTable', 'name')
resources:
dynamoTable:
type: dynamo-db-table
myFunction:
type: function
properties:
allowAccessTo:
- dynamoTable

API reference

LocalScript  API reference
type
Required
properties.executeScript
properties.executeCommand
properties.executeScripts
properties.executeCommands
properties.cwd
properties.pipeStdio
Default: true
properties.connectTo
properties.environment
properties.assumeRoleOfResource
LocalScriptWithBastionTunneling  API reference
type
Required
properties.bastionResource
properties.executeScript
properties.executeCommand
properties.executeScripts
properties.executeCommands
properties.cwd
properties.pipeStdio
Default: true
properties.connectTo
properties.environment
properties.assumeRoleOfResource
BastionScript  API reference
type
Required
properties.bastionResource
properties.executeCommand
properties.executeCommands
properties.cwd
properties.connectTo
properties.environment
properties.assumeRoleOfResource

Contents