lxc-fedora.in revision e5469dadd9fa248fe9992c8323af115f78dbbb27
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# template script for generating fedora container for LXC
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# lxc: linux Container library
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Daniel Lezcano <daniel.lezcano@free.fr>
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Ramez Hanna <rhanna@informatiq.org>
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Michael H. Warfield <mhw@WittsEnd.com>
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# This library is free software; you can redistribute it and/or
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# modify it under the terms of the GNU Lesser General Public
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# License as published by the Free Software Foundation; either
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# version 2.1 of the License, or (at your option) any later version.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# This library is distributed in the hope that it will be useful,
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# but WITHOUT ANY WARRANTY; without even the implied warranty of
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Lesser General Public License for more details.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# You should have received a copy of the GNU Lesser General Public
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# License along with this library; if not, write to the Free Software
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber#Configurations
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Some combinations of the tuning knobs below do not exactly make sense.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# but that's ok.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# If the "root_password" is non-blank, use it, else set a default.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# This can be passed to the script as an environment variable and is
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# set by a shell conditional assignment. Looks weird but it is what it is.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# If the root password contains a ding ($) then try to expand it.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# That will pick up things like ${name} and ${RANDOM}.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# If the root password contians more than 3 consecutive X's, pass it as
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# a template to mktemp and take the result.
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber# If root_display_password = yes, display the temporary root password at exit.
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber# If root_store_password = yes, store it in the configuration directory
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# If root_prompt_password = yes, invoke "passwd" to force the user to change
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# the root password after the container is created.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# If root_expire_password = yes, you will be prompted to change the root
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# password at the first login.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# These are conditional assignments... The can be overridden from the
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# preexisting environment variables...
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Make sure this is in single quotes to defer expansion to later!
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# :{root_password='Root-${name}-${RANDOM}'}
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Now, it doesn't make much sense to display, store, and force change
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# together. But, we gotta test, right???
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Prompting for something interactive has potential for mayhem
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# with users running under the API... Don't default to "yes"
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Expire root password? Default to yes, but can be overridden from
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# the environment variable
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# These are only going into comments in the resulting config...
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# is this fedora?
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Alow for weird remixes like the Raspberry Pi
fad967669817061cda3aafc40be04dcb712a4767Dwight Engen# Use the Mitre standard CPE identifier for the release ID if possible...
33aa351ac13936fb2549403f18a44fed32b2edfbStéphane Graber# This may be in /etc/os-release or /etc/system-release-cpe. We
33aa351ac13936fb2549403f18a44fed32b2edfbStéphane Graber# should be able to use EITHER. Give preference to /etc/os-release for now.
33aa351ac13936fb2549403f18a44fed32b2edfbStéphane Graber# Detect use under userns (unsupported)
33aa351ac13936fb2549403f18a44fed32b2edfbStéphane Graber if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
33aa351ac13936fb2549403f18a44fed32b2edfbStéphane Graber echo "This template can't be used for unprivileged containers." 1>&2
33aa351ac13936fb2549403f18a44fed32b2edfbStéphane Graber echo "You may want to try the \"download\" template instead." 1>&2
fad967669817061cda3aafc40be04dcb712a4767Dwight Engen# Make sure the usual locations are in PATH
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graberexport PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# This is a shell friendly configuration file. We can just source it.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# What we're looking for in here is the ID, VERSION_ID and the CPE_NAME
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber echo "Host CPE ID from /etc/os-release: ${CPE_NAME}"
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graberif [ "${CPE_NAME}" = "" -a -e /etc/system-release-cpe ]
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber CPE_NAME=$(head -n1 /etc/system-release-cpe)
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber CPE_URI=$(expr ${CPE_NAME} : '\([^:]*:[^:]*\)')
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber echo "Host CPE ID from /etc/system-release-cpe: ${CPE_NAME}"
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # Probably a better way to do this but sill remain posix
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # compatible but this works, shrug...
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # Must be nice and not introduce convenient bashisms here.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber ID=$(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:\([^:]*\)')
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber VERSION_ID=$(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\)')
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graberif [ "${CPE_NAME}" != "" -a "${ID}" = "fedora" -a "${VERSION_ID}" != "" ]
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # Only if all other methods fail, try to parse the redhat-release file.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber fedora_host_ver=$( sed -e '/^Fedora /!d' -e 's/Fedora.*\srelease\s*\([0-9][0-9]*\)\s.*/\1/' < /etc/redhat-release )
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # Also kill it in the /etc/selinux/config file if it's there...
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber sed -i '/^SELINUX=/s/.*/SELINUX=disabled/' $rootfs_path/etc/selinux/config
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # Nice catch from Dwight Engen in the Oracle template.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # Wantonly plagerized here with much appreciation.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber if [ -f $rootfs_path/usr/sbin/selinuxenabled ]; then
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber mv $rootfs_path/usr/sbin/selinuxenabled $rootfs_path/usr/sbin/selinuxenabled.lxcorig
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber ln -s /bin/false $rootfs_path/usr/sbin/selinuxenabled
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # This is a known problem and documented in RedHat bugzilla as relating
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # to a problem with auditing enabled. This prevents an error in
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber # the container "Cannot make/remove an entry for the specified session"
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc/pam.d/login
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc/pam.d/sshd
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc/pam.d/crond
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # In addition to disabling pam_loginuid in the above config files
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # we'll also disable it by linking it to pam_permit to catch any
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # we missed or any that get installed after the container is built.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber if [ -f ${rootfs_path}/lib/security/pam_loginuid.so ]
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber if [ -f ${rootfs_path}/lib64/security/pam_loginuid.so ]
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # Set default localtime to the host localtime if not set...
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber if [ -e /etc/localtime -a ! -e ${rootfs_path}/etc/localtime ]
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # if /etc/localtime is a symlink, this should preserve it.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber cp -a /etc/localtime ${rootfs_path}/etc/localtime
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # Deal with some dain bramage in the /etc/init.d/halt script.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # Trim it and make it our own and link it in before the default
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # halt script so we can intercept it. This also preventions package
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # updates from interferring with our interferring with it.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # There's generally not much in the halt script that useful but what's
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # in there from resetting the hardware clock down is generally very bad.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # So we just eliminate the whole bottom half of that script in making
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # ourselves a copy. That way a major update to the init scripts won't
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # This is mostly for legacy distros since any modern systemd Fedora
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # release will not have this script so we won't try to intercept it.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber echo '$command -f' >> ${rootfs_path}/etc/init.d/lxc-halt
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber chmod 755 ${rootfs_path}/etc/init.d/lxc-halt
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane GraberBOOTPROTO=dhcp
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane GraberHOSTNAME=${utsname}
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane GraberNM_CONTROLLED=no
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber cat <<EOF > ${rootfs_path}/etc/sysconfig/network
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane GraberNETWORKING=yes
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane GraberHOSTNAME=${utsname}
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber if [ $release -gt 14 ]; then
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber echo "${utsname}" > ${rootfs_path}/etc/hostname
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber127.0.0.1 localhost.localdomain localhost $utsname
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber::1 localhost6.localdomain6 localhost6
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber # These mknod's really don't make any sense with modern releases of
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber # Fedora with systemd, devtmpfs, and autodev enabled. They are left
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber # here for legacy reasons and older releases with upstart and sysv init.
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 666 ${dev_path}/null c 1 3
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 666 ${dev_path}/zero c 1 5
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 666 ${dev_path}/random c 1 8
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 666 ${dev_path}/urandom c 1 9
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 666 ${dev_path}/tty c 5 0
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 666 ${dev_path}/tty0 c 4 0
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 666 ${dev_path}/tty1 c 4 1
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 666 ${dev_path}/tty2 c 4 2
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 666 ${dev_path}/tty3 c 4 3
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 666 ${dev_path}/tty4 c 4 4
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 600 ${dev_path}/console c 5 1
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 666 ${dev_path}/full c 1 7
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber mknod -m 666 ${dev_path}/ptmx c 5 2
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber # setup console and tty[1-4] for login. note that /dev/console and
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber # /dev/tty[1-4] will be symlinks to the ptys /dev/lxc/console and
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber # /dev/lxc/tty[1-4] so that package updates can overwrite the symlinks.
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber # lxc will maintain these links and bind mount ptys over /dev/lxc/*
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber # since lxc.devttydir is specified in the config.
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber # allow root login on console, tty[1-4], and pts/0 for libvirt
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber echo "# LXC (Linux Containers)" >>${rootfs_path}/etc/securetty
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber echo "lxc/console" >>${rootfs_path}/etc/securetty
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber echo "lxc/tty1" >>${rootfs_path}/etc/securetty
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber echo "lxc/tty2" >>${rootfs_path}/etc/securetty
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber echo "lxc/tty3" >>${rootfs_path}/etc/securetty
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber echo "lxc/tty4" >>${rootfs_path}/etc/securetty
10a5fab6f3ad5cab234b198da31633e41c8ee364Stéphane Graber echo "# For libvirt/Virtual Machine Monitor" >>${rootfs_path}/etc/securetty
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber echo "Setting root password to '$root_password'"
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber echo ${root_password} > ${config_path}/tmp_root_pass
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber echo "Storing root password in '${config_path}/tmp_root_pass'"
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber echo "root:$root_password" | chroot $rootfs_path chpasswd
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # Also set this password as expired to force the user to change it!
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # specifying this in the initial packages doesn't always work.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # Always make sure /etc/resolv.conf is up to date in the target!
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # Rebuild the rpm database based on the target rpm version...
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber chroot ${rootfs_path} yum -y install fedora-release
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber if [[ ! -e ${rootfs_path}/sbin/NetworkManager ]]
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # NetworkManager has not been installed. Use the
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # legacy chkconfig command to enable the network startup
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber sed -i 's/ACTIVE_CONSOLES=.*$/ACTIVE_CONSOLES="\/dev\/console \/dev\/tty[1-4]"/' \
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.sysinit
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.d/rc.sysinit
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.sysinit
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.d/rc.sysinit
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber chroot ${rootfs_path} chkconfig udev-post off
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # This is to make upstart honor SIGPWR. Should do no harm
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber # on systemd systems and some systems may have both.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber cat <<EOF >${rootfs_path}/etc/init/power-status-changed.conf
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# power-status-changed - shutdown on SIGPWR
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graberstart on power-status-changed
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graberexec /sbin/shutdown -h now "SIGPWR received"
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber rm -f ${rootfs_path}/etc/systemd/system/default.target
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber chroot ${rootfs_path} ln -s /dev/null /etc/systemd/system/udev.service
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber chroot ${rootfs_path} ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber chroot ${rootfs_path} ln -s /usr/lib/systemd/system/halt.target /etc/systemd/system/sigpwr.target
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber #dependency on a device unit fails it specially that we disabled udev
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber # sed -i 's/After=dev-%i.device/After=/' ${rootfs_path}/lib/systemd/system/getty\@.service
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber # Actually, the After=dev-%i.device line does not appear in the
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber # Fedora 17 or Fedora 18 systemd getty\@.service file. It may be left
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber # over from an earlier version and it's not doing any harm. We do need
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber # to disable the "ConditionalPathExists=/dev/tty0" line or no gettys are
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber # started on the ttys in the container. Lets do it in an override copy of
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber # the service so it can still pass rpm verifies and not be automatically
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber # updated by a new systemd version. -- mhw /\/\|=mhw=|\/\/
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber sed -e 's/^ConditionPathExists=/# ConditionPathExists=/' \
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber < ${rootfs_path}/lib/systemd/system/getty\@.service \
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber > ${rootfs_path}/etc/systemd/system/getty\@.service
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber # Setup getty service on the 4 ttys we are going to allow in the
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber # default config. Number should match lxc.tty
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber ( cd ${rootfs_path}/etc/systemd/system/getty.target.wants
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber for i in 1 2 3 4 ; do ln -sf ../getty\@.service getty@tty${i}.service; done )
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber### BEGIN Bootstrap Environment Code... Michael H. Warfield /\/\|=mhw=|\/\/
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber# Ok... Heads up. If you're reading these comments, you're either a
0d656b0549e67635ad9c24474b82dfa26e1f4512Stéphane Graber# template owner or someone wondering how the hell I did this (or, worse,
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber# someone in the future trying to maintain it). This code is slightly
9accc2efea59a685942501c13e8eb7a21f74a5f6Stéphane Graber# "evil coding bastard" code with one significant hack / dirty trick
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# that you would probably miss just reading the code below. I'll mark
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# it out with comments.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Because of what this code does, it deserves a lot of comments so people
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# can understand WHY I did it this way...
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Ultimate Objective - Build a Fedora container on a host system which does
fecf101cc4352e9bf60ed3477196146a65b5c4f6Stéphane Graber# not have a (complete compatible) version of rpm and/or yum. That basically
fecf101cc4352e9bf60ed3477196146a65b5c4f6Stéphane Graber# means damn near any distro other than Fedora and Ubuntu (which has rpm and
fecf101cc4352e9bf60ed3477196146a65b5c4f6Stéphane Graber# yum available). Only requirements for this function are rsync and
fecf101cc4352e9bf60ed3477196146a65b5c4f6Stéphane Graber# squashfs available to the kernel. If you don't have those, why are you
fecf101cc4352e9bf60ed3477196146a65b5c4f6Stéphane Graber# even attempting to build containers?
fecf101cc4352e9bf60ed3477196146a65b5c4f6Stéphane Graber# Challenge for this function - Bootstrap a Fedora install bootstrap
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# run time environment which has all the pieces to run rpm and yum and
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# from which we can build targets containers even where the host system
fecf101cc4352e9bf60ed3477196146a65b5c4f6Stéphane Graber# has no support for rpm, yum, or fedora.
fecf101cc4352e9bf60ed3477196146a65b5c4f6Stéphane Graber# Stage 0 - Download a Fedora LiveOS squashfs core (netinst core).
fecf101cc4352e9bf60ed3477196146a65b5c4f6Stéphane Graber# Stage 1 - Extract filesystem from Stage 0 and update to full rpm & yum
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Stage 2 - Use Stage 1 to build a rootfs with python, rpm, and yum.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Stage 2 becomes our bootstrap file system which can be cached
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# and then used to build other arbitrary vesions of Fedora of a
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# given architecture. Note that this only has to run once for
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Fedora on a given architecture since rpm and yum can build other
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# versions. We'll arbitrarily pick Fedora 20 to build this. This
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# will need to change as time goes on.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Programmers Note... A future fall back may be to download the netinst
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# iso image instead of the LiveOS squasfs image and work from that.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# That may be more general but will introduce another substep
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# (mounting the iso) to the stage0 setup.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# This system is designed to be as autonomous as possible so all whitelists
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# and controlls are self-contained.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Initial testing - Whitelist nobody. Build for everybody...
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Initial deployment - Whitelist Fedora.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Long term - Whitelist Fedora, Debian, Ubuntu, CentOs, Scientific, and NST.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# List of distros which do not (should not) need a bootstrap (but we will test
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# for rpm and yum none the less... OS SHOULD be taken from CPE values but
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# Debian / Ubuntu doesn't support CPE yet.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# BOOTSTRAP_WHITE_LIST=""
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber# BOOTSTRAP_WHITE_LIST="fedora debian ubuntu centos scientific sl nst"
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # We need rpm. No rpm - not possible to white list...
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber # We need yum No yum - not possible to white list...
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber if [[ ${WHITE_LISTED} != 0 ]]
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber if [[ ${ID} = ${OS} ]]
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane GraberOS ${ID} is whitelisted. Installation Bootstrap Environment not required.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane GraberFedora Installation Bootstrap Build..."
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane GraberUnable to locate rsync. Cravely bailing out before even attempting to build
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graberan Installation Bootstrap Please install rsync and then rerun this process.
71d3a6590fe665421d7a0026d699b0654ddfc7f6Stéphane Graber [[ -d ${cache_base} ]] || mkdir -p ${cache_base}
cd ${cache_base}
for bootstrap in ${BOOTSTRAP_LIST}
if [[ -d ${bootstrap} ]]
cp /etc/resolv.conf ${bootstrap}/etc/
RC=$?
if [[ 0 == ${RC} ]]
cd ${TMP_BOOTSTRAP_DIR}
# We're going to use the kernel.org mirror for the initial stages...
if [[ ! -f ../LiveOS/squashfs.img ]]
Downloading stage 0 LiveOS squashfs file system from mirrors.kernel.org...
mount -o loop ../LiveOS/squashfs.img squashfs
cd stage1
cp /etc/resolv.conf etc/
rsync -av mirrors.kernel.org::fedora/releases/20/Fedora/$basearch/os/Packages/f/fedora-release-20* .
chroot . yum -y --nogpgcheck --installroot /run/install install python rpm yum
cd ../bootstrap
cp /etc/resolv.conf etc/
RC=$?
if [[ ${RC} != 0 ]]
rm -rf ${TMP_BOOTSTRAP_DIR}
[[ -d ${BOOTSTRAP_DIR}/run/install ]] || mkdir -p ${BOOTSTRAP_DIR}/run/install
mount -o bind ${INSTALL_ROOT} ${BOOTSTRAP_DIR}/run/install
mount -o bind /dev ${BOOTSTRAP_DIR}/dev
mount -t proc proc ${BOOTSTRAP_DIR}/proc
cp /etc/resolv.conf ${BOOTSTRAP_DIR}/etc/
if [ $? -ne 0 ]; then
PKG_LIST="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils fedora-release"
sleep 3
for MIRROR_URL in ${MIRROR_URLS}
RELEASE_RPM=$(curl -L -f "$RELEASE_URL" | sed -e "/fedora-release-${release}-/!d" -e 's/.*<a href=\"//' -e 's/\">.*//' )
if [ $? -ne 0 ]; then
if [ $DOWNLOAD_OK != yes ]; then
mkdir -p ${INSTALL_ROOT}/var/lib/rpm
if ! fedora_get_bootstrap
${BOOTSTRAP_CHROOT}rpm --root ${BOOTSTRAP_INSTALL_ROOT} --initdb
${BOOTSTRAP_CHROOT}rpm --root ${BOOTSTRAP_INSTALL_ROOT} --nodeps -ivh ${BOOTSTRAP_INSTALL_ROOT}/${RELEASE_RPM}
${BOOTSTRAP_CHROOT}yum --installroot ${BOOTSTRAP_INSTALL_ROOT} -y --nogpgcheck install ${PKG_LIST}
RC=$?
cd ${INSTALL_ROOT}
${BOOTSTRAP_CHROOT} db_dump ${BOOTSTRAP_INSTALL_ROOT}/$db | chroot . db_load $db.new
mkdir -p @LOCALSTATEDIR@/lock/subsys/
flock -x 9
if [ $? -ne 0 ]; then
if [ $? -ne 0 ]; then
if [ $? -ne 0 ]; then
if [ $? -ne 0 ]; then
while read LINE
done < $config_path/config.def
lxc.include = @LXCTEMPLATECONFIG@/fedora.common.conf
if [ $? -ne 0 ]; then
if [ ! -e $cache ]; then
flock -x 9
cat <<EOF
[-p|--path=<path>] [-c|--clean] [-R|--release=<Fedora_release>] [--fqdn=<network name of container>] [-a|--arch=<arch of the container>]
-p,--path path to where the container will be created, defaults to @LXCPATH@. The container config will go under @LXCPATH@ in that case
-R,--release Fedora release for the new container. if the host is Fedora, then it will default to the host's release.
eval set -- "$options"
# utsname and hostname = Container_Name.Domain_Name
if [ -n "$needed_pkgs" ]; then
echo "Missing commands: $needed_pkgs"
echo "Please install these using \"sudo yum install $needed_pkgs\""
if [ -z "$path" ]; then
if [ -z "$release" ]; then
echo "This is not a fedora host and release missing, defaulting to 20 use -R|--release to specify release"
if [ -z "$rootfs_path" ]; then
# check for 'lxc.rootfs' passed in through default config by lxc-create
# This configuration (rc.sysinit) is not inconsistent with the systemd stuff
if [ ! -z $clean ]; then
echo "The temporary password for root is: '$root_password'