Stackscript guide?
Hi, I cant find any useful information on how to write stackscripts. E.g:
How to pass parameters
How to log errors and debug
How to get around not having console.
There are lots of example scripts, but most of them are for things like installing LAMP. There seems to be no scripts (which I could find) which were hello world and basic introduction.
I found this: https://www.linode.com/docs/platform/stackscripts/
Which has some of this info, but is missing how to debug (e.g. where do the errors go, What happens when the script fails etc), and a set of hello world examples demonstrating the various features.
4 Replies
What is a StackScript?
A StackScript is a script that you create with a new disk. That script is shimmed into the filesystem, in distribution specific ways, such that it will run on the first boot of that disk, and never again.
How and When it works
The shimming differs between supported distributions, but generally takes the form of a temporary "getty" daemon replacement. Since the getty is normally one of the last things to get started on boot-up this ensures that the network is ready by the time your script is invoked.
When you define your StackScript, you use a UNIX style shebang indicating what command interpreter should process the script.
Hello World
The Hello World of StackScripts would look like this:
#!/bin/sh
echo Hello World
You can find the output of this command in your LISH or GLISH console.
Screen output can easily be lost, so a more realistic Hello World would persist some change to disk.
My StackScript
I have a StackScript that I use on all of my new Linodes. When creating a new Linode, I provide my Github username (and any other Github usernames separated by commas) to automatically create accounts for those usernames, reusing their Github registered SSH Public Keys for authentication.
https://www.linode.com/stackscripts/view/10079
Variables
In the second line of that StackScript, I instruct the script to request a variable at disk creation time.
Both the Linode Manager and the Linode API provide means to provide values for these StackScript values.
# <UDF name="gh_username" Label="GitHub Username" example="GitHub User account to create with sudo access (use spaces or commas for multiple accounts)" />
UDF name/value pairs are passed as environment variables when your StackScript is executed. When this script is executed within the Linode, an environment variable of GH_USERNAME
will contain the value that was provided in the Manager or API. There are more UDF details available in the StackScripts Guide.
Including other StackScripts
StackScripts can include other StackScripts by referencing their ID in UDF within the body of the StackScript source. For example,
#!/bin/sh
FILENAME='<ssinclude StackScriptID="1">'
source $FILENAME
# or simply
source <ssinclude StackScriptID="1">
The reference to <ssinclude StackScriptID="1">
will be replaced with a file path that contains the referenced StackScript at the time the disk is being deployed (typically from a source image, like Debian).. This replacement will work for a StackScript written in any language, not just shell scripts. Keep in mind, all StackScripts must begin with a shebang.
Public StackScripts and StackScripts on your own account can be referenced in this way.
Logging
Logging can be performed using regular system logging commands, like logger
(man logger
for more on that).
To add onto this I've used bash debugging to see how a StackScript deploy went through the Lish console. You can set bash debugging with this line at the beginning of your StackScript:
set -x
After the StackScript is finished running you can page up in the Lish console ("fn+shift+up arrow" on OSX) to see which commands may have failed.
This was done out of laziness instead of redirecting output for many commands to syslog or log files. Lazy but it works!
The StackScript Bash Library
We recently released a pretty large update to the StackScript Bash Library, which adds compatibility for a bunch of newer distributions that were not previously supported, as well as a handful of useful new functions. Below, you can find a list of the new functions, as well as the currently supported distributions:
New functions
configure_basic_firewall()
- Sets basic default rules, including opening port 22 for SSHget_started()
- Runs through the steps in "Getting Started" (https://www.linode.com/docs/getting-started)secure_server()
- Runs through the steps in "How to Secure your Server" (https://www.linode.com/docs/security/securing-your-server)save_firewall()
- Persist firewall rulesadd_port()
- Opens firewall ports for all supported distributions. Has support for both iptables and FirewallDenable_fail2ban()
- Enables fail2ban with default settingslamp_stack()
- Configures a LAMP Stack. This is based off of a couple of our guides, but since it supports multiple distros, I did have to stray in some partswordpress_install()
- This is not a new function, but it has been updated to support more distributionsenable_passwordless_sudo()
- Enables passwordless sudo accessdebian_upgrade()
- This should be the only thing that'll work "differently" for currently written scripts. I encountered an issue with APT in which runningapt-get upgrade
right afterapt-get update
caused issues, so they were separated into two functionssystem_detect_distro()
- This function runs automatically when the library is imported, and does not need to be called manually. It determines what distribution is in use (Ubuntu, CentOS, etc), which family that distribution belongs to (Debian/RedHat), and which version is installed (e.g. Debian 10 vs 8). That data is then stored in an associative array called${detected_distro[@]}
. When using the library's native functions, it is not necessary to reference this at all, as it's already accounted for in each function, but it is available for use should you decide to write your own platform-independent StackScripts.
I encourage you to check out the library itself, as there are usage instructions for each function. You'll also notice that some of these functions (e.g. secure_server
) simply call other functions in the library, so running some of them manually may not be necessary if you're using one of those functions.
Update list of compatible distributions
- Debian 8-10
- Ubuntu 16.04-19.04 (19.10 probably works, but was released after this was completed - looking for feedback on this one)
- Fedora 27-30 (31 may work too, but was released after completion - also looking for feedback here)
- CentOS 7 - CentOS 8 compatibility hasn't yet been attempted
Setting the Timezone using get_started
It occurred to me that I did not include instructions in the get_started
function outlining how to enter the timezone. The function uses timedatectl
, so you can enter any compatible timezone for that command. For example, a Linode in our Newark datacenter would be in America/New_York
, or US/Eastern
. You can obtain a list of compatible timezone values by logging into an existing Linode and running timedatectl list-timezones
, or listing the contents of /usr/share/zoneinfo
:
ls /usr/share/zoneinfo