Can I run a StackScript after creating a Linode?
Is it possible to run a StackScript even after my Linode has been created?
2 Replies
While there is no way to directly invoke a StackScript after creating your Linode, you definitely could modify one to work after the fact.
StackScripts can be just about any script, with the addition of the ability to declare UDF variables, as well as source other StackScripts. UDF variables could be replaced with input via command line arguments, hardcoded values, or even input from a file. I'm not as familiar with Python, but if the script uses Bash, you can source another StackScript using the ssinclude
directive:
source <ssinclude StackScriptID=12345>
To use the referenced StackScript after creating your Linode, you would need to manually copy it to a local file, and source it that way in your script instead, removing or commenting out the original source <ssinclude ...>
line:
# source <ssinclude StackScriptID=12345>
# Source the StackScript locally
source '/path/to/downloaded/script'
The interpreter used by the StackScript is specified using the #!
(called a 'shebang') at the top of the script, and could be Bash, Python, or any other interpreter that's available on the OS you've installed. For example, you may see something similar to one of the examples below at the top of the script. This will let you know which interpreter is being used:
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/env bash
#!/usr/bin/env python
The last thing to account for when converting a StackScript to a normal script is to replace any UDF variables that need to be defined with normal variable definitions. UDF variables are generally defined at the top of the script, inside of a comment (lines that start with #
), and define the fields that you fill out when creating a Linode using a StackScript in the Cloud Manager, as well as the data you pass to the StackScript when deploying a Linode from the API/CLI.
I've found 2 clean ways to approach this. The first is to simply define the variables inside of your script. For example, if a Bash StackScript requires the UDF variables $USERNAME
and $PASSWORD
, you would put something similar to this near the top of the script, before any UDF variables are referenced:
USERNAME='my_username'
PASSWORD='S3cur3P@ssw0rD'
The second method, and my personal preference, is to create a second file in which you define the UDF variables, and source it into the converted script. For example, you can create a file called vars.sh
(or whatever you prefer to name it), and enter something similar to the following into it:
#!/usr/bin/env bash
USERNAME='my_username'
PASSWORD='S3cur3P@ssw0rD'
You would then need to source it into the script. To do that, you can add a line near the top of the script (again, before any UDF variables are referenced). This example assumes that your file is called vars.sh
, and that it lives in the same directory as the script:
source './vars.sh`
You can also use command-line arguments to account for UDF variables, but I personally consider this a bit of a messy approach, as it requires typing potentially sensitive data into the command line when calling it:
./my_converted_script.sh "my_username" "S3cur3P@ssw0rD"
All of this said, unless there is some specific reason that you must run the script in the Linode's current configuration, it will likely save you some time and effort if you simply re-create the Linode using the StackScript. It's also worth noting that if you download a StackScript to source it locally, you could miss out on updates to the script, which may not be desirable if you plan on deploying another server with that script at some point in the future.
A note on security when using these methods
Storing a password inside of a file in plaintext isn't really the most secure practice, so you may instead wish to put code into the script which generates a password at random. Just remember to update the script so that you can retrieve the password, since it isn't stored in the file using this method. To use a randomly generated password, you can replace PASSWORD='S3cur3P@ssw0rD'
with something like the following:
PASSWORD="$(date +%s | sha256sum | base64 | head -c 32 ; echo)"
There are a number of different ways to randomly generate a password, and this is just one example. I found this article, which discusses 10 different ways you can generate a random password in a Bash script. Whichever command you go with, it should follow the form:
PASSWORD="$(command of your choosing)"
This runs the command to generate your password in a subshell, and captures its output into the $PASSWORD
variable.
You then need to obtain the password somehow. In a StackScript, outputting the password to the screen may be unreliable, as StackScript output is sometimes lost, but in the context of a normal script it works just fine. My recommendation is to use printf
to output it to the screen at the end of the script:
printf "The password for %s is %s\n", "$USERNAME" "$PASSWORD"
Just remember to store that password somewhere safe, because it won't show a second time.