Five Easy Steps
These are the steps to relatively easily create a new potluck flavour by reusing our code (of course you can also create flavours from scratch if you prefer):
- You should get the basic idea of pot flavours
- In your
/usr/local/etc/pot/flavours
, create a new flavour file based on the template below - If your flavour is a blocking, i.e.
nomad
, flavour, create the additional flavour files as well (copy & paste) - Test your new image locally
- Submit via github
That’s it!
How Does It Work?
These are the high-level steps of the jail creation process if it is based on our template below:
pot
creates the jail and runs the flavour jail script.- The jail script…
- …installs the packages within the jail and sets up
/etc/rc.conf
- …creates a script named
/usr/local/bin/cook
and ensures it gets run on each jail start - …if needed, copies config file (templates) into the jail
- …installs the packages within the jail and sets up
- Via
pot set-env
or command line parameters tocook
, all the configuration settings required in the jail are passed to it, e.g. hostnames to connect to, paths, names etc. - When the jail is started the first time,
/usr/local/bin/cook
…- …creates all the configuration files & setting, taking the values from the environment
- …starts all the services the first time
- On each subsequent run,
/usr/local/bin/cook
is inactive and the jail services are run based on the configuration
That means that the jail can be recreated by just repeating these steps from scratch, e.g. when new package versions are available.
Also, steps 1 & 2 are executed by the potluck Jenkins scripts, packaging the results into an image file. This image file can then be downloaded and installed by customizing the image with steps 3 & 4.
Flavour Files
Flavour Shell Script
The flavour shell script installs all packages in the jail and configures them (i.e. creates the config files).
With a simple configuration knob, you can create both standard jails (i.e. jails that run in the background as soon as you start them) or blocking jails that can also be run via nomad
(i.e. jails where pot start
does not return until the jail stops, see this document for more information).
If you don’t know the difference, you want to create a standard, non-blocking jail, that is the same logic all the other jail management tools also support.
Copy the following example as <flavour>.sh
into your /usr/local/etc/pot/flavours
directory and adjust it. Also have a look at the configuration files available at github for inspiration. Not all images use the latest flavour templates, but e.g. the postfix-backupmx-nomad image uses the most current v2.0 template.
You will notice that there are two ways to pass parameters in the file below: Via environment (pot set-env
) and via command line parameter to the cook
script (used for nomad
job description files, have a look e.g. at the postfix-backupmx-nomad documentation) that are processed via getopts
.
#!/bin/sh
# POTLUCK TEMPLATE v2.0
# EDIT THE FOLLOWING FOR NEW FLAVOUR:
# 1. RUNS_IN_NOMAD - yes or no
# 2. Create a matching <flavour> file with this <flavour>.sh file that
# contains the copy-in commands for the config files from <flavour>.d/
# Remember that the package directories don't exist yet, so likely copy to /root
# 3. Adjust package installation between BEGIN & END PACKAGE SETUP
# 4. Adjust jail configuration script generation between BEGIN & END COOK
# Configure the config files that have been copied in where necessary
# Set this to true if this jail flavour is to be created as a nomad (i.e. blocking) jail.
# You can then query it in the cook script generation below and the script is installed
# appropriately at the end of this script
RUNS_IN_NOMAD=true
# -------------- BEGIN PACKAGE SETUP -------------
[ -w /etc/pkg/FreeBSD.conf ] && sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
ASSUME_ALWAYS_YES=yes pkg bootstrap
touch /etc/rc.conf
sysrc sendmail_enable="NO"
# Install packages
pkg install -y postfix
pkg clean -y
# -------------- END PACKAGE SETUP -------------
#
# Create configurations
#
#
# Now generate the run command script "cook"
# It configures the system on the first run by creating the config file(s)
# On subsequent runs, it only starts sleeps (if nomad-jail) or simply exits
#
# ----------------- BEGIN COOK ------------------
echo "#!/bin/sh
RUNS_IN_NOMAD=$RUNS_IN_NOMAD
# No need to change this, just ensures configuration is done only once
if [ -e /usr/local/etc/pot-is-seasoned ]
then
# If this pot flavour is blocking (i.e. it should not return),
# we block indefinitely
if [ \$RUNS_IN_NOMAD ]
then
/bin/sh /etc/rc
tail -f /dev/null
fi
exit 0
fi
# ADJUST THIS: STOP SERVICES AS NEEDED BEFORE CONFIGURATION
/usr/local/etc/rc.d postfix stop || true
# No need to adjust this:
# If this pot flavour is not blocking, we need to read the environment first from /tmp/environment.sh
# where pot is storing it in this case
if [ -e /tmp/environment.sh ]
then
. /tmp/environment.sh
fi
#
# ADJUST THIS BY CHECKING FOR ALL VARIABLES YOUR FLAVOUR NEEDS:
#
# Convert parameters to variables if passed (overwrite environment)
while getopts h:n:d:b: option
do
case \"\${option}\"
in
h) HOSTNAME=\${OPTARG};;
n) MYNETWORKS=\${OPTARG};;
d) RELAYDOMAINS=\${OPTARG};;
b) SMTPDBANNER=\${OPTARG};;
esac
done
# Check config variables are set
if [ -z \${MYNETWORKS+x} ];
then
echo 'MYNETWORKS is unset - setting it to 192.168.0.0/16,10.0.0.0/8' >> /var/log/cook.log
echo 'MYNETWORKS is unset - setting it to 192.168.0.0/16,10.0.0.0/8'
MYNETWORKS=\"192.168.0.0/16,10.0.0.0/8\"
fi
if [ -z \${RELAYDOMAINS+x} ];
then
echo 'RELAYDOMAINS is unset - see documentation how to configure this flavour' >> /var/log/cook.log
echo 'RELAYDOMAINS is unset - see documentation how to configure this flavour'
exit 1
fi
if [ -z \${SMTPDBANNER+x} ];
then
echo 'SMTPDBANNER is unset - setting it to \"\\\$myhostname ESMTP \\\$mail_name (\\\$mail_version)\"' >> /var/log/cook.log
echo 'SMTPDBANNER is unset - setting it to \"\\\$myhostname ESMTP \\\$mail_name (\\\$mail_version)\"'
SMTPDBANNER=\"\\\$myhostname ESMTP \\\$mail_name (\\\$mail_version)\"
fi
if [ -z \${HOSTNAME+x} ];
then
echo 'HOSTNAME is unset - setting it to \"backupmx\"' >> /var/log/cook.log
echo 'HOSTNAME is unset - setting it to \"backupmx\"'
HOSTNAME=\"backupmx\"
fi
# ADJUST THIS BELOW: NOW ALL THE CONFIGURATION FILES NEED TO BE ADJUSTED & COPIED:
# main.cf
# Variable in main.cf are replaced by the variables passed to the script, e.g.
# $MYNETWORKS is replaced by the MYNETWORKS parameter
[ -w /root/main.cf ] && sed -i '' \"s&\\\$MYNETWORKS&\$MYNETWORKS&\" /root/main.cf
[ -w /root/main.cf ] && sed -i '' \"s/\\\$RELAYDOMAINS/\$RELAYDOMAINS/\" /root/main.cf
[ -w /root/main.cf ] && sed -i '' \"s/\\\$SMTPDBANNER/\$SMTPDBANNER/\" /root/main.cf
[ -w /root/main.cf ] && sed -i '' \"s/\\\$HOSTNAME/\$HOSTNAME/\" /root/main.cf
mkdir -p /usr/local/etc/postfix
mv /root/main.cf /usr/local/etc/postfix
mkdir -p /usr/local/etc/mail
install -m 0644 /usr/local/share/postfix/mailer.conf.postfix /usr/local/etc/mail/mailer.conf
[ -w /etc/syslog.conf ] && sed -i '' \"s/# mail.info/mail.info/\" /etc/syslog.conf
/etc/rc.d/syslogd restart
# ADJUST THIS: START THE SERVICES AGAIN AFTER CONFIGURATION
sysrc postfix_enable=\"YES\"
/usr/local/etc/rc.d/postfix restart
# Do not touch this:
touch /usr/local/etc/pot-is-seasoned
# If this pot flavour is blocking (i.e. it should not return), there is no /tmp/environment.sh
# created by pot and we now after configuration block indefinitely
if [ \$RUNS_IN_NOMAD ]
then
/bin/sh /etc/rc
tail -f /dev/null
fi
" > /usr/local/bin/cook
# ----------------- END COOK ------------------
# ---------- NO NEED TO EDIT BELOW ------------
chmod u+x /usr/local/bin/cook
#
# There are two ways of running a pot jail: "Normal", non-blocking mode and
# "Nomad", i.e. blocking mode (the pot start command does not return until
# the jail is stopped).
# For the normal mode, we create a /usr/local/etc/rc.d script that starts
# the "cook" script generated above each time, for the "Nomad" mode, the cook
# script is started by pot (configuration through flavour file), therefore
# we do not need to do anything here.
#
# Create rc.d script for "normal" mode:
echo "#!/bin/sh
#
# PROVIDE: cook
# REQUIRE: LOGIN
# KEYWORD: shutdown
#
. /etc/rc.subr
name=cook
rcvar=cook_enable
load_rc_config $name
: ${cook_enable:=\"NO\"}
: ${cook_env:=\"\"}
command=\"/usr/local/bin/cook\"
command_args=\"\"
run_rc_command \"\$1\"
" > /usr/local/etc/rc.d/cook
chmod u+x /usr/local/etc/rc.d/cook
if [ $RUNS_IN_NOMAD = false ]
then
# This is a non-nomad (non-blocking) jail, so we need to make sure the script
# gets started when the jail is started:
# Otherwise, /usr/local/bin/cook will be set as start script by the pot flavour
echo "cook_enable=\"YES\"" >> /etc/rc.conf
fi
Copying in Config File Templates & Nomad Flavours
In case you create blocking (nomad
) flavours, you should create a second <flavour2> file and an additional flavour that starts the command. You probably can simply copy & paste the files below.
Also, if you have config file templates that you want to copy into the jail, use such a file.
<flavour> for nomad
(it needs to have the same name as <flavour>.sh with only the filename extension being different):
set-attribute -A persistent -V OFF
set-attribute -A no-rc-script -V ON
<flavour> showing how to copy in config file templates (or any other file you need in the jail). All config file templates need to be stored in a directory called <flavour>.d (so that the Jenkins script finds them):
set-attribute -A persistent -V OFF
set-attribute -A no-rc-script -V ON
copy-in -s /usr/local/etc/pot/flavours/postfix-backupmx-nomad.d/main.cf -d /root
The cook
script can then move the files into the right places and also replace variables where necessary. Don’t copy the files to /tmp
as they will be removed during jail start before you can move them somewhere else.
For nomad
, you also need a second flavour that sets the script being generated by the <flavour>.sh above as the script being run by pot
:
set-cmd -c "/usr/local/bin/cook"
Testing The Flavours
- Create the jail:
sudo pot create -b 12.1 -t single -p myjail -N public-bridge -f <flavour>
…or as blocking jail, with also adding the second flavour:
sudo pot create -b 12.1 -t single -p myjail -N public-bridge -f <flavour> -f <flavour2>
- Set the variables you have defined in the <flavour> cook script:
pot set-env -p myjail -E MYFIRSTVAR=value
- Start the jail & test away:
pot start myjail