# Scripting overview

## What is a script?

A script is a set of commands that execute without compiling. Bash is a popular scripting language for Linux and Mac. The famous *Hello World* example, which prints simple text,  looks like this in bash:

```bash
#!/bin/bash
echo "Hello World"
```

{% hint style="info" %}
This page is only intended as an overview to scripting in Instruqt. To learn how to implement scripts, refer to the following pages:

* [Track scripts](https://docs.instruqt.com/sandboxes/lifecycle-scripts/add-software-and-packages-to-a-track)
* [Challenge scripts](https://docs.instruqt.com/sandboxes/lifecycle-scripts/add-a-script-to-check-challenge-execution)
  {% endhint %}

## Lifecycle scripts

From setup to teardown, all tracks follow the same lifecycle, which is split between a "track" and "challenge" component.

The *track* lifecycle consists of the following stages:

* Setup&#x20;
* Cleanup

The *challenge* lifecycle consists of:

* Setup
* Check
* Solve
* Cleanup

### Lifecycle script types

#### Setup

Setup scripts run at the beginning of a track or challenge, before user interaction begins. These scripts are commonly used for environment setup, variable initialization, software installation, and other setup tasks.

#### Check

Check scripts run when the user clicks the "Check" button to move to the next challenge. If the exit status is zero (success), then the user receives a message and the challenge ends. If the exit status is non-zero (failure), then the user is provided feedback and the challenge does not end.

It is recommended to use the `set -euxo pipefail`command in Linux bash scripts, as the `fail-message`can be customized to provide specific feedback to the learner.

{% hint style="info" %}
The "Check" button will be labeled "Next" if no check script is defined.
{% endhint %}

#### Solve

Solve scripts enable users to skip to arbitrary challenges within a track by completing the steps in the solve scripts of each preceding challenge. This allows the track environment to "fast-forward" to the required state for the desired challenge.

For example, a three-challenge track may have a challenge each for installation, configuration, and upgrading a software product. In order to configure the software, it must first be installed, so a solve script for the first challenge would perform those tasks required to enable the next challenge (configuration) to take place.

#### Cleanup

Cleanup scripts run at the end of a track or challenge, after a user completes the section in question. This can be used to reinitialize variables or environments to known-good states to mitigate user experimentation, to cleanup extraneous files that may have been created, or other housekeeping tasks between challenges.

Track cleanup scripts run after the user has finished or idled out of a track, just before Instruqt destroys the sandbox environment, so typically, no cleanup is necessary here. It may be useful, however, to use this script to trigger external webhooks or APIs to perform actions on an external platforms. One example might be triggering an external SaaS system to remove a temporary account used during the track.

The following is a visual representation of the lifecycle stages a track and its challenges go through:

![The track and challenge lifecycle stages](https://2094212015-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MGJDYBXyftBAZb1Wq0e%2Fuploads%2FkIUsyIg2CLUkHQMVXLA5%2FLifecycleScripts.png?alt=media\&token=76f179a4-40cf-444d-bd76-cd13c4ca1b71)

Content developers create lifecycle scripts that run on the sandbox hosts to:

* Set up and clean up the sandbox environment and the challenges.
* Check and give your learners feedback on their challenge solution.
* Automatically solve a challenge when a learner skips a challenge.&#x20;

### Script attributes

* All lifecycle scripts are optiona&#x6C;*.*
* Any scripting language can be used to write the scripts—for example, [bash](https://en.wikipedia.org/wiki/Bash_\(Unix_shell\)) or [Python](https://www.python.org/), where bash is the most common choice for Instruqt.
* Instruqt determines if a script was successful by checking the returned script exit code:
  * If the exit code is `0`, Instruqt marks the script as successful.&#x20;
  * If the exit code is **not** `0`, Instruqt marks the script as unsuccessful.
* Scripts run in alphanumeric order, based on hostnames. (e.g the setup script of `host-a` will execute before the setup script of `host-b`.)

### **Script Size Limits & Best Practices**

* The maximum size of a lifecycle script is **5 MB**.
* Avoid embedding **binary files** inside lifecycle scripts to keep them lightweight and maintainable.

### Script timeouts

Every lifecycle script has a maximum duration it can take to complete. After that the script times out and will exit with an error. Scripts are not retried when it times out.

The timeouts for scripts are:

| Script            | Timeout |
| ----------------- | ------- |
| Track Setup       | 55 min  |
| Track Cleanup     | 55 min  |
| Challenge Setup   | 55 min  |
| Challenge Check   | 1 min   |
| Challenge Solve   | 55 min  |
| Challenge Cleanup | 55 min  |

### Script parameters

The Instruqt platform injects a set of environment variables, which are available as parameters in every script:

<table data-header-hidden data-full-width="false"><thead><tr><th width="387">Environment Variable</th><th>Description</th></tr></thead><tbody><tr><td>Environment Variable</td><td>Description</td></tr><tr><td><code>INSTRUQT_TRACK_ID</code></td><td>The ID of the track</td></tr><tr><td><code>INSTRUQT_TRACK_SLUG</code></td><td>The slug of the track</td></tr><tr><td><code>INSTRUQT_CHALLENGE_ID</code></td><td>(Optional) The ID of the challenge that the script is running on. This can be empty, in case of a track cleanup script.</td></tr><tr><td><code>INSTRUQT_PARTICIPANT_ID</code></td><td>The ID of the participant. This value is guaranteed to be unique for every play of a track, i.e. when a user starts the same track twice, the IDs will differ. <br>Participant is the sandbox identifier, not a user.</td></tr><tr><td><code>INSTRUQT_TRACK_INVITE_ID</code></td><td>(Optional) The ID of the <a href="../../tracks/share/track-invite-links">track invite</a>. It is only  present if the user accessed the track via an invite link.</td></tr><tr><td><code>INSTRUQT_USER_ID</code></td><td>(Optional) The ID of the user. This value uniquely identifies a user.<br><br>Empty in a Hot Start track setup script.</td></tr><tr><td><code>INSTRUQT_USER_NAME</code></td><td>(Optional) The full name of the user (as they entered it when creating their account). This value is only be present if the user has given consent to share their details. For example, if a learner started a track through a track invite.<br><br>Empty in a Hot Start track setup script.</td></tr><tr><td><code>INSTRUQT_USER_EMAIL</code>  </td><td>(Optional) The email address of the user. This value is only be present if the user has given consent to share their details. For example, if a learner started a track through a track invite.<br><br>Empty in a Hot Start track setup script.</td></tr><tr><td><code>INSTRUQT_PRIVACY_POLICY_CONSENT</code>  </td><td>Whether the user accepted the organization's privacy policy.</td></tr></tbody></table>

#### Example

The following challenge setup script writes the learner's name and the challenge id to the logging:&#x20;

{% tabs %}
{% tab title="Bash" %}

```bash
#!/bin/bash
echo $INSTRUQT_USER_NAME started challenge $INSTRUQT_CHALLENGE_ID
```

{% endtab %}
{% endtabs %}

If you play a track that contains this script and [view the track log](https://docs.instruqt.com/tracks/manage/viewing-logs), you will see a log entry with the learner's name and the challenge id.
