Write a custom script for use with StackScripts

At the core of all StackScripts is a custom script that is written to perform a certain task (or collection of tasks). These custom scripts are written in a language that's supported by the targeted Linux distributions. Writing a custom script for a StackScript is largely the same as writing a custom script that you would execute from the command line or another program. This guide explains some important considerations as well as the special features that StackScripts support.

Before you begin

When creating a StackScript, most of the time is spent writing the deployment script itself. This script runs the first time a Compute Instance boots up and lets you configure the system to fit your precise needs and requirements. Before you write the script, consider the following:

  • What is the purpose of your script? The first question you should ask is what purpose will your script serve. Do you want to build a web server? Are you building a script to take care of securing new servers? Consider each task you want your script to perform.

  • Which scripting language should be used for your script? You can write the StackScript in any language that the distribution supports out of the box. Specifically, you need to specify the interpreter that is used to execute the script. Common scripting languages are bash and python.

  • Which Linux distributions should the script support? Since each distribution bundles different core software, the commands needed to install applications or configure networking vary between distributions. You need to determine which distributions you want to have available when deploying the Compute Instance. Then, you can customize your script to include commands for those distributions.

  • Which dynamic variables do you want the user to set when deploying a Compute Instance? Determine what information you wish to collect during deployment. These user variables can be defined through the use of UDF fields within the script. All UDF fields are visible in Cloud Manager when creating a Compute Instance based on the StackScript.

Components of a StackScript

  • Interpreter (required): The scripting language and interpreter needed to execute the script. In the example below, the bash interpreter is used. See Set the Language and Interpreter.

    #!/bin/bash
    
  • Declaration of user-defined fields (optional): These fields are presented to the user in Cloud Manager during the deployment process. See Declare User-Defined Fields (UDFs).

    # <UDF name="example-variable" Label="Example Variable" example="This is an example UDF variable for a StackScript" />
    
  • Import external StackScripts (optional): You can optionally import other StackScripts to reuse code. See Import a StackScript.

    source <ssinclude StackScriptID="1">
    
  • Script: The rest of the StackScript should your deployment script. This preforms the tasks that you've outlined in the Before You Begin section. For example, the script below updates the system and installs PHP, NGINX, and MariaDB.

    apt-get update && apt-get upgrade -y
    apt-get install -y php nginx mariadb-server
    

Set the language and interpreter

The primary requirement for your scripts is that the interpreter needed to execute your script should exist in each Linux distribution you are targeting. While bash is an obvious choice that's supported by all distribution images, you may choose another scripting language.

The first line of the script must include a shebang followed by the path to the interpreter that should be use.

  • Bash: #!/bin/bash
  • Python: #!/usr/bin/env python
  • Python 3: #!/usr/bin/python3

Declare user-defined fields (UDFs)

The StackScript system provides a basic markup specification that interfaces with the Akamai cloud computing deployment process. This syntax allows users to customize the behavior of a StackScript on a per-deployment basis. When a StackScript contains a user-defined field (UDF), Cloud Manager presents the UDF as a form field. The user can then insert a corresponding custom value into the field. The values and their related variables are inserted into the script's environment when used to deploy a new Compute Instance.

📘

UDF fields are only usable by scripts written in bash.

Use the following format to insert a UDF tag into a StackScript.

# <udf name="[variable-name]" label="[field-label]" default="[default-value]" example="[helper-text]" />

📘

The UDF tags are commented out to prevent execution errors, as the StackScript system parses the tags without removing them.

UDF attributes

A UDF tag accepts the following attributes:

  • Variable name (required):

    name="[variable-name]"

    The variable name is the string you wish to use to reference this variable within the StackScript. The string must be alphanumeric (can include underscores), less than 64 characters in length, and be unique within the StackScript.

    📘

    If you would like to create a masked password input field, use the word password anywhere in the UDF name attribute.

  • Field label (required):

    label="[field-label]"

    The label attribute is used when displaying the field to the user in Cloud Manager. This should be a short string that clearly indicates what the field is used for. If needed, you can also enter helper text using the example attribute.

  • Helper text (optional):

    example="[helper-text]"

    This text is displayed in Cloud Manager underneath the field. It should be used to further explain to the user what the field is used for.

  • Select one (optional):

    oneOf="[value1],[value2],..."

    A comma separated list of acceptable values for the field. These values are displayed either as radio boxes (if just 2 values are provided) or within a dropdown menu (if 3 or more values are provided). Only one value can be selected by the user. This cannot be used within the manyOf attribute (discussed below) within the same UDF tag.

  • Select multiple (optional):

    manyOf="[value1],[value2],..."

    A comma separated list of acceptable values for the field in any quantity, combination, or order. These values are displayed within a dropdown menu in Cloud Manager. Multiple values can be selected by the user. This cannot be used within the oneOf attribute (discussed above) within the same UDF tag.

  • Default value (optional):

    default="[default-value]"

    This defines the default value for this UDF. If no value is specified by the user during deployment, this default value is used. The default value is displayed to the user within Cloud Manager.

    • String (neither oneOf or manyOf are used): The default value can be any string and is displayed as plain text within the form field in Cloud Manager.
    • Select one (oneOf attribute is defined): The default value needs to correspond with a single value defined in the oneOf attribute. This value is pre-selected in the radio field or dropdown box in Cloud Manager.
    • Select multiple (manOf attribute is defined): The default value needs to correspond with one or more values defined in the manyOf attribute. If setting multiple values as the default, delimit them with a comma. These values are pre-selected in the dropdown box in Cloud Manager.

Default environment variables

StackScripts provide a set of default environment variables that you can use to provide your script with information about the Linode it has deployed.

Environment VariableDescription
LINODE_IDThe deployed Compute Instance's ID number.
LINODE_LISHUSERNAMEThe deployed Compute Instance's full Linode Shell (LISH) accessible name.
LINODE_RAMThe RAM available on this Compute Instance's plan.
LINODE_DATACENTERIDThe ID number of the data center containing the Compute Instance. You can use the Linode API to see a list of all data center IDs.

Set your environment variables using an external file

It is possible to set your script's environment variables using externally hosted files. The example Bash script uses the wget utility to download two files named base.env and $IPADDR.env from the external site http://example.com/. The source command loads the downloaded files into the script.

...
IPADDR=$(/sbin/ifconfig eth0 | awk '/inet / { print $2 }' | sed 's/addr://')

wget http://example.com/base.env --output-document=/tmp/base.env
wget http://example.com/$IPADDR.env --output-document=/tmp/system.env

source /tmp/base.env
source /tmp/system.env
...

📘

The files you reference within your script must exist and be accessible via HTTP. Also, ensure that the files you host externally do not contain any sensitive information.

Import a StackScript

Your scripts can import any other StackScript, including those from within your own account or those shared with the community. This lets you reuse code between StackScripts, minimizing the amount of new code you might need to write.

  • Bash:

    source <ssinclude StackScriptID="[ID]">
    
  • Other scripting languages:

    <ssinclude StackScriptID="[ID]">
    ./ssinclude-[ID]
    

In the example syntax above, replace [ID] with the ID corresponding to the StackScript you wish to use. You can find the ID by viewing the StackScript in Cloud Manager and copying the value within the StackScript ID field, as shown below:

Screenshot of the StackScript ID in <<CLOUD_PORTAL>>

Using the StackScript bash library

Linode provides a StackScript Bash Library that includes a set of functions that perform various common tasks users might wish to execute on their Compute Instances. This script creates the functions, but does not run them. A new StackScript can import the Bash Library and then execute functions from it.

📘

The Linode StackScript Bash Library's ID number is 1.

#!/bin/bash
source <ssinclude StackScriptID="1">
system_update
system_install_package php wget nginx

Example StackScript

The file below displays an example of a simple script that executes some basic set up steps on a Compute Instance. Review the example's comments for details on what each line of the script does.

#!/bin/bash
# This block defines the variables the user of the script needs to provide
# When deploying using this script.
# # #<udf name="hostname" label="the hostname for the new linode.">
# Hostname=
# #<udf name="fqdn" label="the new linode's fully qualified domain name">
# Fqdn=

# This sets the variable $ipaddr to the IP address the new Linode receives.
IPADDR=$(/sbin/ifconfig eth0 | awk '/inet / { print $2 }' | sed 's/addr://')

# This updates the packages on the system from the distribution repositories.
apt-get update
apt-get upgrade -y

# This section sets the hostname.
echo $HOSTNAME > /etc/hostname
hostname -F /etc/hostname

# This section sets the fully qualified domain name (fqdn) in the hosts file.
echo $IPADDR $FQDN $HOSTNAME >> /etc/hosts