How Do I Quickly Create a New Potluck Flavour?

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):

  1. You should get the basic idea of pot flavours
  2. In your /usr/local/etc/pot/flavours, create a new flavour file based on the template below
  3. If your flavour is a blocking, i.e. nomad, flavour, create the additional flavour files as well (copy & paste)
  4. Test your new image locally
  5. 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:

  1. pot creates the jail and runs the flavour jail script.
  2. The jail script…
    1. …installs the packages within the jail and sets up /etc/rc.conf
    2. …creates a script named /usr/local/bin/cook and ensures it gets run on each jail start
    3. …if needed, copies config file (templates) into the jail
  3. Via pot set-env or command line parameters to cook, all the configuration settings required in the jail are passed to it, e.g. hostnames to connect to, paths, names etc.
  4. When the jail is started the first time, /usr/local/bin/cook
    1. …creates all the configuration files & setting, taking the values from the environment
    2. …starts all the services the first time
  5. 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

  1. 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>

  1. Set the variables you have defined in the <flavour> cook script:

pot set-env -p myjail -E MYFIRSTVAR=value

  1. Start the jail & test away:

pot start myjail

This site © Honeyguide Group (Pty) Ltd, all the hosted software their respective license owners 2020 - Disclaimer