Stacktape

Sign upSign up



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

Copy

scripts:
buildWeb:
type: local-script
properties:
executeCommand: npx gatsby build
hooks:
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 or executeScripts 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(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.

Copy

scripts:
buildWeb:
type: local-script
properties:
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 Typescript
    • python for Python
  • Only one of executeScript, executeScripts, executeCommand or executeCommands can be configured.

Copy

scripts:
sendSlackNotification:
type: local-script
properties:
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 ID
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
});
})();

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

Copy

scripts:
buildWeb:
type: local-script
properties:
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 Typescript
    • python for Python
  • Only one of executeScript, executeScripts, executeCommand or executeCommands can be configured.

Copy

scripts:
sendSlackNotification:
type: local-script
properties:
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-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:
primaryInstance:
instanceSize: db.t3.micro
credentials:
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 endpoint
const databaseConnectionString = process.env.STP_MY_DATABASE_CONNECTION_STRING;
const client = new DbClient({ connectionString: databaseConnectionString });
// perform migrations with the client
client.close();

Example pseudo migration script

Graphical overview of tunneling
Graphical overview of tunneling

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-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:
primaryInstance:
instanceSize: db.t3.micro
credentials:
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 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

Copy

scripts:
dbScript:
type: local-script
properties:
# environment variable $STP_MY_DATABASE_CONNECTION_STRING is injected thanks to 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

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

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
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
BastionScript  API reference
type
Required
properties.bastionResource
properties.executeCommand
properties.executeCommands
properties.cwd
properties.connectTo
properties.environment

Need help? Ask a question on Discord or info@stacktape.com.