Skip to content

instruqt/track-rsync-intro

Repository files navigation

Rsync Intro --- An Instruqt Example Track

This is an example three challenge Instruqt track, designed to show off the basics of how a track works.

Requirements

You must have a Team Secret called IGGYS_SSH_PRIVATE_KEY_BASE64 which was created from the output of running

TMP=$(mktemp -d); ssh-keygen -t ed25519 -f "${TMP}/id_ed25519" -N "" >/dev/null; base64 -b 0 < "${TMP}/id_ed25519"; rm -rf "${TMP}"

NOTE: Your variant of base64 or equivalent may have different command-line flags, the output must have no line breaks.

Annotated Track Guide

The basic unit of content on Instruqt is a track. This is what a learner interacts with. Every time a learner starts a track, they get a unique, isolated instance of that track. Track instances are ephemeral: once the track is finished, or a timeout reached, the track instance is deprovisioned and the resources within it go away.

An Instruqt track has three primary components:

  1. A sandbox which contains the resources this track needs, like virtual machines, containers, virtual web browsers, and cloud accounts
  2. Challenges which are the individual steps a learner progresses through to complete a track, which can also reference assets like images or videos.
  3. Lifecycle scripts which are scripts that run at well-defined points within the lifecycle of a track, and are responsible for setting and cleaning up tracks, and setting up, cleaning up, solving, and checking challenges.

Rounding this out are two metadata files, config.yml and track.yml.

We'll cover each of these in turn.

track.yml

The track.yml file contains various track metadata, such as its title and description, a "slug" (the URL component which identifies this particular track), and configuration for the owner organization, the developers for this track, and configuration of timeouts and how challenges are displayed. You can also set track tags, a label attached to a lab which can be used to group similar content together and filter on the team content page.

Rounding out this file are some autogenerated fields, id and checksum, which the Instruqt platform will set for you.

config.yml

The config.yml file defines the sandbox resources required for this track. In our track here, we have three types of resources.

Sandbox Virtual Machines

The virtualmachines key defines any number of virtual machines which will be provisioned in each instance of a track when it is launched. In our case, we have two, a VM named workstation and a VM named fileserver. These names are used to reference VMs within challenge assignments (for example, you can have a terminal window in a challenge assignment, and you specify which VM the terminal runs on). Additionally, within a sandbox you can use the VM names as dns names.

While we do not use them in this track, you can also use containers

Instruqt leverages the Google Cloud Platform, and both VMs and containers can reference public images, or you can create custom VM or container. Instruqt supports both Linux and Windows VMs, including support for Remote Desktop within a challenge.

This track uses two custom VM images. If you are curious, you can check out the Packer directory, which contains the definitions of the custom VM images used in this track. Packer is not an Instruqt product, and is outside the scope of this annotation. You can build custom VM images with any tool which allows you to produce GCP images, or you can use the built-in Instruqt Host Images tool.

If you install a bunch of software or have a lot of setup tasks which are the same for every instance of a track you are using the VM image in, it makes sense to build a custom image, as you will do that work once, and a track instance will be able to start immediately with everything installed, etc. But, if you only have a small amount of things to customize, you can easily do it in a track startup script (discussed later).

Virtual Web Browsers

A virtual web browser allows you to display a website in a tab within a track challenge. Instruqt also supports websites directly; but if a given website will not run within an iframe you must use a virtual web browser.

Here we configure our virtual web browser to show the rsync documentation website.

Secrets

A secret is a way to store and use sensitive values in a lifecycle script (discussed later). You might store credentials or API tokens in a secret. Secrets are defined at a the team level by team owners, and can be used by multiple tracks.

Secrets show up as environment variables in lifecycle scripts, and only lifecycle scripts. They are not visible to the end learner unless you copy them somewhere accessible by the learner.

In our track, we create a user iggy on both the fileserver and workstation, and want that user to be able to ssh between both hosts, so we store an ssh private key as a secret and use it during track setup scripts to install it in the proper place.

Cloud Accounts

While not used in this track, you can also include any number of cloud accounts in a track.

Challenges

Within a given track are one or more challenges. A challenge is an individual step the learner must complete along the way to finish the track. In our example track, we have three challenges, an introduction to rsync, a demonstration of incremental updates, and selective transfers. We will talk about challenge lifecycle scripts later on, for now, the key component in each challenge is the assignment.md file. We will walk through this file for Challenge 02 - Incremental Update.

Challenge Metadata

At the top of the assignment.md file is a section of yaml which contains the challenge metadata, and defines which tabs are exposed in this challenge:

  1. The title is the displayed title of this challenge
  2. The slug is the URL fragment which references this particular challenge.
  3. The tabs section defines the tabs which are visible in this challenge. A tab can point at a website, a service running on a VM or container within this track instance sandbox, a simple code editor, a terminal, or a virtual browser. In this particular challenge, we have one tab to a terminal on the workstation host, and another to a virtual browser to display the rsync documentation webpage.

Challenge Assignment

The remainder of the assignment.md file, after the second ---, is the assignment, the instructions presented to the learner as they go through this challenge. This is in Markdown, which you can edit by hand or use the built-in Markdown editor.

Assets

Note that the first item in the challenge 02 assignment text is ![rsync logo](../assets/rsync-logo.png). This is a normal Markdown reference to show an image or video, which leverages the Instruqt platform support for assets. Any image or video placed in the assets/ directory in your track and referenced like this example will be automatically uploaded and rendered in your track.

Runtime variables

Note also that rather than hardcoding the directory paths the learner is supposed to reference, you see the following:

[[ Instruqt-Var key="WORKSTATION_DST_DIR" hostname="workstation" ]]

These are runtime variables, which allow you to set variables in your sandbox hosts, and leverage them in your assignment text. As you'll see later when we cover lifecycle scripts, we set the runtime variables WORKSTATION_DST_DIR and FILESERVER_SRC_DIR. Here we do it for ease of updating the track if we decide to change the source and destination directories, but you can use these for any dynamic content you may have in your track. For example, you may provision temporary credentials in a lifecycle script, if you set them as a runtime variable you can surface those to your learner in a challenge assignment.

Lifecycle Scripts

The third component of an Instruqt track are lifecycle scripts. These are scripts which run at certain well defined points of a track's lifecycle, and are divided into two categories: track-level scripts and challenge-level scripts.

These scripts run behind the scenes, invisible to your learner, and can be leveraged by you to do things which have to happen per instance of a running track. These tend to be shell scripts, although on Linux sandbox hosts and containers they can be scripting language which is installed in the sandbox (for example, Python or Ruby), on Windows VM PowerShell is supported.

Track Setup and Cleanup

Track-level scripts are placed in the track_scripts/ directory at the top level of your track. They can run at track setup, when a sandbox is created, and at track cleanup, when the sandbox is deprovisioned. Each sandbox host can have it's own script, setup scripts are named setup-<host name>, and cleanup scripts are named cleanup-<host name>. In our track, we do not have any track cleanup scripts, only setup scripts, but both of our sandbox hosts have setup scripts.

Since our hosts are called fileserver and workstation, our setup scripts are setup-fileserver and setup-workstation, respectively.

In our example track here, we mostly use the track setup scripts to install an SSH key for our test user iggy, but you could use these scripts to do any setup or cleanup which has to be done when the track sandbox is running. For tracks which use cloud accounts, this tends to be where resources are provisioned within those accounts; since each track gets its own ephemeral cloud account, that setup cannot happen until the sandbox is created.

While we do not have any cleanup scripts here, these tend to be used for cleanup of any external ephemeral resources. For example, if you create a temporary account on a SaaS platform for use in a track, you can clean it up and keep things tidy in a track cleanup script.

Our setup-workstation script also leverages two Instruqt features, secrets, and runtime variables.

Secrets

We covered how you add secrets to a track above when we looked at the track config.yml. The setup-workstation script shows how you use them within a lifecycle script: they show up as environment variables. So, when we added this section to our config.yml:

secrets:
- name: IGGYS_SSH_PRIVATE_KEY_BASE64

we make available an environment variable which we use in the setup-workstation script on this line:

echo "${IGGYS_SSH_PRIVATE_KEY_BASE64}" | base64 -d > id_ed25519

Note that only secrets configured in your config.yml are available to your track, you may have several secrets configured in your Instruqt team but only the ones you ask for will be exposed to your lifecycle scripts.

Note also that these values are available only in the lifecycle scripts. They are not available to the learner, even if there have a terminal on a given sandbox host.

Runtime Variables

We previously talked about using Runtime variables in the Challenge Assignment section, but did not cover how to set them.

agent variable set FILESERVER_SRC_DIR "${FILESERVER_SRC_DIR}"
agent variable set WORKSTATION_DST_DIR "${WORKSTATION_DST_DIR}"

This section of the setup-workstation track lifecycle script is how we set those runtime variables. As mentioned above, we can use runtime variables in challenge assignments to have dynamic assignment content. It is also possible to use runtime variables within other lifecycle scripts after they are set, as long as you are on the same sandbox host. For example, in a later lifecycle script which runs on the workstation host you could run the command agent variable get FILESERVER_SRC_DIR to retrieve the value set above.

Challenge Scripts

In addition to track lifecycle scripts, each challenge has its own lifecycle scripts, which again can run on any (or multiple) sandbox hosts.

A challenge setup script runs when the learner starts a challenge, and they are called setup-<host name>. Looking again at this track's second challenge, the setup-workstation script runs on the workstation host, and does setup specific to this challenge. In our case, we want to set up a scenario where certain files are removed and we want to restore them, our setup script copies all of the files and then deletes the ones we want, to set up the challenge for the user.

A challenge check script runs when the learner clicks on the "Check" button in an assignment, and they are called check-<host name>. A check script allows you to give your learner feedback by allowing you to verify that they completed the steps necessary to successfully complete this challenge. If the return code of the script is 0, the check successfully completed and the learner can move on, any other return code indicates an error. You can use the fail-message helper script to return feedback to the user.

A challenge solve script has two uses. First, you can enable skipping within challenges, which can be useful if a learner is stuck on a particular challenge, or if they return to a previously partially completed track and want to return to where they left off.

Second, they can be used for track testing, by allowing you to simulate a learner's actions when using the instruqt track test command.

These scripts are called solve-<host name>; in this particular challenge we have a solve-workstation script. The challenge 03 solve script is a particularly good example:

# We run *every* command we tell iggy to run

sudo -u iggy rsync -av --stats --include '*.lbl' "fileserver:${FILESERVER_SRC_DIR}" "${WORKSTATION_DST_DIR}"
sudo -u iggy rm -rf "${WORKSTATION_DST_DIR}"
sudo -u iggy rsync -av --stats --exclude '*' "fileserver:${FILESERVER_SRC_DIR}" "${WORKSTATION_DST_DIR}"
sudo -u iggy rsync -av --stats --exclude '*' --include '*.lbl' "fileserver:${FILESERVER_SRC_DIR}" "${WORKSTATION_DST_DIR}"
sudo -u iggy rsync -av --stats --include '*.lbl' --exclude '*' "fileserver:${FILESERVER_SRC_DIR}" "${WORKSTATION_DST_DIR}"
sudo -u iggy rsync -av --stats --include '*.lbl' --include '*/' --exclude '*' "fileserver:${FILESERVER_SRC_DIR}" "${WORKSTATION_DST_DIR}"

A challenge cleanup script runs at the end of each challenge, and can be used to cleanup any actions performed during that challenge if necessary before moving to the next challenge. These scripts are called cleanup-<host name>.

About

An example track which teaches you very little about rsync. Made with love by the Value Engineering Team.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors