--- /dev/null
+#!/bin/sh
+
+
+USAGE="Usage: $(basename $0) <container name>"
+
+if [ $# -ne 1 ]
+then
+ echo "$USAGE" >&2
+ exit 1
+fi
+
+CONTAINER_NAME=$(basename $1)
+CONTAINER_OS=$(echo $CONTAINER_NAME | sed 's/^.*\.\([^\.]*\)$/\1/')
+CONTAINER_BASENAME=$(basename $CONTAINER_NAME .$CONTAINER_OS)
+case "$CONTAINER_OS" in
+ "f29")
+ DNF_RELEASEVER=29
+ PREV_CONTAINER_OS="f28"
+ ;;
+ "f28")
+ DNF_RELEASEVER=28
+ PREV_CONTAINER_OS="f27"
+ ;;
+ *)
+ echo "Unknown operating system: $CONTAINER_OS" >&2
+ exit 1
+ ;;
+esac
+
+SCRIPT_PATH=$(dirname $(realpath $0))
+BASE_PATH=$(dirname $SCRIPT_PATH)
+BACKUPS_PATH=$BASE_PATH/backups
+BUILD_PATH=$BASE_PATH/build
+FILESYSTEMS_PATH=$BASE_PATH/filesystems
+SOURCES_PATH=$BASE_PATH/sources
+
+if [ -f /etc/lxc/lxc.conf ]
+then
+ LXC_PATH=$(grep '^lxc.lxcpath' /etc/lxc/lxc.conf \
+ | cut -f 2 -d '=' | tr -d ' ')
+else
+ echo "No lxc system configuration found" >&2
+ exit 1
+fi
+
+CONTAINER_PATH=$LXC_PATH/$CONTAINER_NAME
+CONTAINER_BUILD_PATH=$BUILD_PATH/$CONTAINER_NAME
+CONTAINER_FILESYSTEMS_PATH=$FILESYSTEMS_PATH/$CONTAINER_NAME
+CONTAINER_SOURCE_PATH=$SOURCES_PATH/$CONTAINER_NAME
+
+source $SCRIPT_PATH/functions
+RC=$?
+if [ $RC -ne 0 ]
+then
+ echo "Could not source functions: $RC" >&2
+ exit $RC
+fi
+
+################################################################
+# exit if no source exists for the container #
+################################################################
+if [ ! -d $CONTAINER_SOURCE_PATH ]
+then
+ echo "No source found for $CONTAINER_NAME" >&2
+ exit 1
+fi
+source $CONTAINER_SOURCE_PATH/envvars
+
+################################################################
+# exit if the container build directory already exists #
+################################################################
+if [ -d $CONTAINER_BUILD_PATH ]
+then
+ echo "The build directory already exists." >&2
+ exit 1
+fi
+
+echo "Starting at $(date)"
+
+################################################################
+# create and populate the container build directory #
+################################################################
+echo "Creating the container build directory."
+mkdir --parents $CONTAINER_BUILD_PATH/rootfs
+
+echo "Creating container config and hooks."
+sed --expression="s|__CONTAINER_FILESYSTEMS_PATH__|$CONTAINER_FILESYSTEMS_PATH|" \
+ --expression="s|__CONTAINER_PATH__|$CONTAINER_PATH|" \
+ <$CONTAINER_SOURCE_PATH/config \
+ >$CONTAINER_BUILD_PATH/config
+if [ -d $CONTAINER_SOURCE_PATH/hooks ]
+then
+ cp --archive $CONTAINER_SOURCE_PATH/hooks $CONTAINER_BUILD_PATH
+fi
+
+################################################################
+# execute preinstall phase #
+################################################################
+echo "Executing preinstall phase."
+preinstall $CONTAINER_NAME \
+ $CONTAINER_BUILD_PATH/rootfs \
+ $CONTAINER_SOURCE_PATH
+
+################################################################
+# install packages into the container #
+################################################################
+DNF_CONFIG=$SCRIPT_PATH/dnf.conf.fedora
+dnf --assumeyes \
+ --config=$DNF_CONFIG \
+ --disableplugin=fastestmirror \
+ --disablerepo=* \
+ --enablerepo=local-* \
+ --installroot=$CONTAINER_BUILD_PATH/rootfs \
+ --releasever=$DNF_RELEASEVER \
+ install $BASE_PACKAGES $SPEC_PACKAGES
+dnf --assumeyes \
+ --config=$DNF_CONFIG \
+ --disableplugin=fastestmirror \
+ --disablerepo=* \
+ --enablerepo=local-* \
+ --installroot=$CONTAINER_BUILD_PATH/rootfs \
+ --releasever=$DNF_RELEASEVER \
+ clean all
+
+################################################################
+# execute postinstall phase #
+################################################################
+echo "Executing postinstall phase."
+postinstall $CONTAINER_NAME \
+ $CONTAINER_BUILD_PATH/rootfs \
+ $CONTAINER_SOURCE_PATH
+
+################################################################
+# find the old container if it exists #
+################################################################
+OLD_CONTAINER_NAME=
+lxc-ls --line | grep "^${CONTAINER_NAME}$" >/dev/null 2>&1
+if [ $? -eq 0 ]
+then
+ OLD_CONTAINER_NAME=$CONTAINER_NAME
+fi
+if [ -z "$OLD_CONTAINER_NAME" ]
+then
+ PREV_CONTAINER_NAME="${CONTAINER_BASENAME}.$PREV_CONTAINER_OS"
+ lxc-ls --line | grep "^${PREV_CONTAINER_NAME}$" >/dev/null 2>&1
+ if [ $? -eq 0 ]
+ then
+ OLD_CONTAINER_NAME=$PREV_CONTAINER_NAME
+ fi
+fi
+if [ -n "$OLD_CONTAINER_NAME" ]
+then
+ OLD_CONTAINER_PATH=$LXC_PATH/$OLD_CONTAINER_NAME
+ OLD_CONTAINER_BACKUP_PATH=$BACKUPS_PATH/$OLD_CONTAINER_NAME
+fi
+
+################################################################
+# rename the backup of the old container if needed #
+################################################################
+if [ -n "$OLD_CONTAINER_NAME" ]
+then
+ if [ -d $OLD_CONTAINER_BACKUP_PATH ]
+ then
+ rm -Rf ${OLD_CONTAINER_BACKUP_PATH}.old
+ mv $OLD_CONTAINER_BACKUP_PATH ${OLD_CONTAINER_BACKUP_PATH}.old
+ fi
+fi
+
+################################################################
+# shut down the old container if needed #
+################################################################
+if [ -n "$OLD_CONTAINER_NAME" ]
+then
+ OLD_CONTAINER_STATE=$(lxc-info --name=$OLD_CONTAINER_NAME --state 2>/dev/null | cut -f 2 -d ':' | tr -d ' ')
+ case "$OLD_CONTAINER_STATE" in
+ "RUNNING")
+ echo "Stopping container $OLD_CONTAINER_NAME"
+ lxc-stop --name=$OLD_CONTAINER_NAME
+ echo "Stopped container $OLD_CONTAINER_NAME"
+ ;;
+ "STOPPED")
+ ;;
+ *)
+ echo "Unknown container state: $OLD_CONTAINER_STATE" >&2
+ exit 1
+ ;;
+ esac
+fi
+
+################################################################
+# back up the old container if needed #
+################################################################
+if [ -n "$OLD_CONTAINER_NAME" ]
+then
+ mv $OLD_CONTAINER_PATH $OLD_CONTAINER_BACKUP_PATH
+fi
+
+################################################################
+# move the new container to its place #
+################################################################
+mv $CONTAINER_BUILD_PATH $CONTAINER_PATH
+
+################################################################
+# start up the new container #
+################################################################
+echo "Starting container $CONTAINER_NAME"
+lxc-start --name=$CONTAINER_NAME --daemon
+
+echo "Waiting for container $CONTAINER_NAME to start up."
+lxc-wait --name=$CONTAINER_NAME --state=RUNNING
+
+################################################################
+# execute firstboot phase #
+################################################################
+echo "Executing firstboot phase."
+firstboot $CONTAINER_NAME \
+ $CONTAINER_PATH/rootfs \
+ $CONTAINER_SOURCE_PATH
+
+echo "Finishing at $(date)"
--- /dev/null
+preinstall()
+{
+ CONTAINER_NAME=$1
+ CONTAINER_ROOTFS=$2
+ CONTAINER_SOURCE_PATH=$3
+
+ if [ -d $CONTAINER_SOURCE_PATH/preinstall ]
+ then
+ cp --archive $CONTAINER_SOURCE_PATH/preinstall $CONTAINER_ROOTFS
+ chmod 755 $CONTAINER_ROOTFS/preinstall/*.sh
+ for SCRIPT in $CONTAINER_ROOTFS/preinstall/*.sh
+ do
+ $SCRIPT
+ done
+ fi
+
+ mkdir $CONTAINER_ROOTFS/dev
+ mkdir $CONTAINER_ROOTFS/proc
+ mount -o bind /dev $CONTAINER_ROOTFS/dev
+ mount -t proc proc $CONTAINER_ROOTFS/proc
+}
+
+postinstall()
+{
+ CONTAINER_NAME=$1
+ CONTAINER_ROOTFS=$2
+ CONTAINER_SOURCE_PATH=$3
+
+ if [ -d $CONTAINER_SOURCE_PATH/postinstall ]
+ then
+ cp --archive $CONTAINER_SOURCE_PATH/postinstall $CONTAINER_ROOTFS
+ chmod 755 $CONTAINER_ROOTFS/postinstall/*.sh
+ for SCRIPT in $CONTAINER_ROOTFS/postinstall/*.sh
+ do
+ POSTINSTALL_SCRIPT=$(echo $SCRIPT | sed "s|^$CONTAINER_ROOTFS||")
+ chroot $CONTAINER_ROOTFS $POSTINSTALL_SCRIPT
+ done
+ fi
+
+ umount $CONTAINER_ROOTFS/dev
+ umount $CONTAINER_ROOTFS/proc
+}
+
+firstboot()
+{
+ CONTAINER_NAME=$1
+ CONTAINER_ROOTFS=$2
+ CONTAINER_SOURCE_PATH=$3
+
+ if [ -d $CONTAINER_SOURCE_PATH/firstboot ]
+ then
+ cp --archive $CONTAINER_SOURCE_PATH/firstboot $CONTAINER_ROOTFS
+ chmod 755 $CONTAINER_ROOTFS/firstboot/*.sh
+ for SCRIPT in $CONTAINER_ROOTFS/firstboot/*.sh
+ do
+ FIRSTBOOT_SCRIPT=$(echo $SCRIPT | sed "s|^$CONTAINER_ROOTFS||")
+ echo lxc-attach --name=$CONTAINER_NAME -- $FIRSTBOOT_SCRIPT
+ lxc-attach --name=$CONTAINER_NAME -- $FIRSTBOOT_SCRIPT
+ done
+ fi
+}