[PATCH] liblxc: add scripts/lxc-fedora.in (WAS: Re: [PATCH] liblxc: Update lxc-debian to use the lenny release)

Matt Helsley matthltc at us.ibm.com
Tue Feb 10 00:28:27 PST 2009


On Mon, 2009-02-09 at 15:43 -0800, Dan Smith wrote:
> DL> It may be possible to use yum like debootstrap for an minbase
> DL> fedora install.
> 
> Yep, something like the following should work:
> 
>   root=/path/to/tmproot
>   mkdir -p $root/var/lib/rpm
>   rpm --root $root --initdb
>   rpm --root $root -Uvfh --nodeps http://fedora.osuosl.org/linux/releases/10/Fedora/i386/os/Packages/fedora-release-10-1.noarch.rpm
>   yum --installroot=$root -y groupinstall Base

Looks familiar! ;) I was intrigued by this idea last weekend so I
started such a script. However I only tested it as far as creating a
semi-correct rootfs. With the exception of network configs most of the
configs are still written as for debian. For example I know the selinux
policy enforcement settings need to move, the inittab needs to be
replaced by the proper upstart configs, etc.

Of course it's based heavily on Daniel's excellent lxc-debian script.

Signed-off-by: Matt Helsley <matthltc at us.ibm.com>
---
 configure.in          |    1 
 scripts/Makefile.am   |    1 
 scripts/lxc-fedora.in |  404 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 406 insertions(+)

Index: lxc/configure.in
===================================================================
--- lxc.orig/configure.in
+++ lxc/configure.in
@@ -90,6 +90,7 @@ AC_CONFIG_FILES([
 
 	scripts/Makefile
 	scripts/lxc-debian
+	scripts/lxc-fedora
 	scripts/lxc-sshd
 
         src/Makefile
Index: lxc/scripts/Makefile.am
===================================================================
--- lxc.orig/scripts/Makefile.am
+++ lxc/scripts/Makefile.am
@@ -1,3 +1,4 @@
 bin_SCRIPTS = \
 	lxc-debian \
+	lxc-fedora \
 	lxc-sshd
Index: lxc/scripts/lxc-fedora.in
===================================================================
--- /dev/null
+++ lxc/scripts/lxc-fedora.in
@@ -0,0 +1,404 @@
+#!/bin/bash
+# set -ex
+
+DISTRO="fedora"
+CACHE="@LOCALSTATEDIR@/cache/lxc/${DISTRO}"
+
+# Default container name
+NAME="fedora"
+CONFFILE="lxc.conf"
+MNTFILE="mount.conf"
+UTSNAME=
+IPV4="172.20.0.21"
+GATEWAY="172.20.0.1"
+
+# These paths are within the container so do not need to obey configure prefixes
+INITTAB="/etc/inittab"
+FSTAB="/etc/fstab"
+SSHD_CONFIG="/etc/ssh/sshd_config"
+
+################################################################################
+#                    DISTRO custom configuration files
+################################################################################
+
+# custom selinux
+
+write_distro_selinux() {
+    mkdir -p ${ROOTFS}/selinux
+    echo 0 > ${ROOTFS}/selinux/enforce
+}
+
+# custom fstab
+
+write_distro_fstab() {
+cat <<EOF > ${ROOTFS}/${FSTAB}
+tmpfs  /dev/shm   tmpfs  defaults  0 0
+EOF
+}
+
+# custom inittab
+
+write_distro_inittab() {
+cat <<EOF > ${ROOTFS}/${INITTAB}
+id:3:initdefault:
+si::sysinit:/etc/init.d/rcS
+l0:0:wait:/etc/init.d/rc 0
+l1:1:wait:/etc/init.d/rc 1
+l2:2:wait:/etc/init.d/rc 2
+l3:3:wait:/etc/init.d/rc 3
+l4:4:wait:/etc/init.d/rc 4
+l5:5:wait:/etc/init.d/rc 5
+l6:6:wait:/etc/init.d/rc 6
+# Normally not reached, but fallthrough in case of emergency.
+z6:6:respawn:/sbin/sulogin
+1:2345:respawn:/sbin/getty 38400 console
+c1:12345:respawn:/sbin/getty 38400 tty1 linux
+c2:12345:respawn:/sbin/getty 38400 tty2 linux
+c3:12345:respawn:/sbin/getty 38400 tty3 linux
+c4:12345:respawn:/sbin/getty 38400 tty4 linux
+EOF
+}
+
+# custom network configuration
+write_distro_network() {
+cat <<EOF > ${ROOTFS}/etc/sysconfig/network-scripts/ifcfg-lo
+DEVICE=lo
+IPADDR=127.0.0.1
+NETMASK=255.0.0.0
+NETWORK=127.0.0.0
+# If you're having problems with gated making 127.0.0.0/8 a martian,
+# you can change this to something else (255.255.255.255, for example)
+BROADCAST=127.255.255.255
+ONBOOT=yes
+NAME=loopback
+EOF
+cat <<EOF > ${ROOTFS}/etc/sysconfig/network-scripts/ifcfg-eth0
+DEVICE=eth0
+BOOTPROTO=static
+HWADDR=52:54:00:12:34:56
+ONBOOT=yes
+HOSTNAME=${UTSNAME}
+NM_CONTROLLED=no
+TYPE=Ethernet
+IPADDR=${IPV4}
+NETWORK=$(ipcalc -sn ${IPV4} 255.255.255.0)
+GATEWAY=${GATEWAY}
+BROADCAST=$(ipcalc -sb ${IPV4} 255.255.255.0)
+NETMASK=255.255.255.0
+EOF
+}
+
+# custom hostname
+
+write_distro_hostname() {
+cat <<EOF > ${ROOTFS}/sysconfig/network
+NETWORKING=yes
+HOSTNAME=${UTSNAME}
+EOF
+}
+
+# custom sshd configuration file
+
+write_distro_sshd_config() {
+cat <<EOF > ${ROOTFS}/${SSHD_CONFIG}
+Port 22
+Protocol 2
+HostKey /etc/ssh/ssh_host_rsa_key
+HostKey /etc/ssh/ssh_host_dsa_key
+UsePrivilegeSeparation yes
+KeyRegenerationInterval 3600
+ServerKeyBits 768
+SyslogFacility AUTH
+LogLevel INFO
+LoginGraceTime 120
+PermitRootLogin yes
+StrictModes yes
+RSAAuthentication yes
+PubkeyAuthentication yes
+IgnoreRhosts yes
+RhostsRSAAuthentication no
+HostbasedAuthentication no
+PermitEmptyPasswords yes
+ChallengeResponseAuthentication no
+EOF
+}
+
+################################################################################
+#                        lxc configuration files
+################################################################################
+
+write_lxc_configuration() {
+cat <<EOF > ${CONFFILE}
+lxc.utsname = ${UTSNAME}
+lxc.tty = 4
+lxc.network.type = veth
+lxc.network.flags = up
+lxc.network.link = br0
+lxc.network.name = eth0
+lxc.mount = ${MNTFILE}
+lxc.rootfs = ${ROOTFS}
+lxc.cgroup.devices.deny = a
+# /dev/null and zero
+lxc.cgroup.devices.allow = c 1:3 rwm
+lxc.cgroup.devices.allow = c 1:5 rwm
+# consoles
+lxc.cgroup.devices.allow = c 5:1 rwm
+lxc.cgroup.devices.allow = c 5:0 rwm
+lxc.cgroup.devices.allow = c 4:0 rwm
+lxc.cgroup.devices.allow = c 4:1 rwm
+# /dev/{,u}random
+lxc.cgroup.devices.allow = c 1:9 rwm
+lxc.cgroup.devices.allow = c 1:8 rwm
+# /dev/pts/* - pts namespaces are "coming soon"
+lxc.cgroup.devices.allow = c 136:* rwm
+lxc.cgroup.devices.allow = c 5:2 rwm
+# rtc
+lxc.cgroup.devices.allow = c 254:0 rwm
+EOF
+}
+
+write_lxc_mounts() {
+cat <<EOF > ${MNTFILE}
+
+EOF
+}
+
+create() {
+
+    # choose a container name, default is already in shell NAME variable
+    echo -n "What is the name for the container ? [${NAME}] "
+    read _NAME_
+
+    if [ ! -z "${_NAME_}" ]; then
+	NAME=${_NAME_}
+    fi
+
+    # choose a hostname, default is the container name
+    echo -n "What hostname do you wish for this container ? [${NAME}] "
+    read _UTSNAME_
+
+    if [ ! -z "${_UTSNAME_}" ]; then
+	UTSNAME=${_UTSNAME_}
+    else
+	UTSNAME=${NAME}
+    fi
+
+    # choose an ipv4 address, better to choose the same network than
+    # your host
+    echo -n "What IP address do you wish for this container ? [${IPV4}] "
+    read _IPV4_
+
+    if [ ! -z "${_IPV4_}" ]; then
+	IPV4=${_IPV4_}
+    fi
+
+    # choose the gateway ip address
+    echo -n "What is the gateway IP address ? [${GATEWAY}] "
+    read _GATEWAY_
+
+    if [ ! -z "${_GATEWAY_}" ]; then
+	GATEWAY=${_GATEWAY_}
+    fi
+
+    # the rootfs name will be build with the container name
+    ROOTFS="./rootfs.${NAME}"
+
+    # check if the rootfs does already exist
+    if [ ! -e "${ROOTFS}" ]; then
+	    mkdir -p @LOCALSTATEDIR@/lock/subsys/
+	(
+	    flock -n -x 200
+
+
+	    RES=$?
+	    if [ "${RES}" != "0" ]; then
+		echo "Cache repository is busy."
+		break
+	    fi
+
+	    # check the mini distro was not already downloaded
+	    echo -n "Checking cache download ..."
+	    if [ ! -e "${CACHE}/rootfs" ]; then
+
+		echo "not cached"
+
+		# Rather than write a special yum config we just make the
+		# default RPM and yum layout in ${CACHE}. The alternative is
+		# to copy /etc/yum/yum.conf or /etc/yum.conf and fiddle with
+		# some settings.
+		mkdir -p "${CACHE}/partial/var/lib/rpm"
+		mkdir -p "${CACHE}/partial/var/log"
+		touch "${CACHE}/partial/var/log/yum.log"
+
+		RELEASE="$(yum info ${DISTRO}-release | \
+			awk -F '[[:space:]]*:[[:space:]]*' \
+				'/^Release/ { release = $2 }
+				/^Version/ { version = $2 }
+				END { print version "-" release }')"
+		PKG="${DISTRO}-release.noarch.rpm"
+		RPM="rpm --root \"${CACHE}/partial\""
+
+		echo "Initializing RPM cache ..."
+		${RPM} --initdb
+		echo "Downloading ${DISTRO} Release ${RELEASE} description ..."
+		yumdownloader --destdir="${CACHE}/partial" "${DISTRO}-release.noarch.rpm" && \
+		${RPM} --nodeps -ihv "${CACHE}/partial/${DISTRO}-release*.noarch.rpm"
+		echo "Downloading ${DISTRO} minimal ..."
+		yum --installroot="${CACHE}/partial" -y groupinstall Base
+		RESULT=$?
+		if [ "${RESULT}" != "0" ]; then
+		    echo "Failed to download the rootfs, aborting."
+		    exit 1
+		fi
+		mv "${CACHE}/partial" "${CACHE}/rootfs"
+		echo "Download complete."
+	    else
+		echo "Found."
+	    fi
+
+            # make a local copy of the mini
+	    echo -n "Copying rootfs ..."
+	    cp -a ${CACHE}/rootfs ${ROOTFS} && echo "Done." || exit
+	) 200> "@LOCALSTATEDIR@/lock/subsys/lxc"
+    fi
+
+write_lxc_mounts
+
+write_lxc_configuration
+
+write_distro_inittab
+
+write_distro_hostname
+
+write_distro_fstab
+
+write_distro_network
+
+write_distro_sshd_config
+
+write_distro_selinux
+
+ at BINDIR@/lxc-create -n ${NAME} -f ${CONFFILE}
+RES=$?
+
+# remove the configuration files
+rm -f ${CONFFILE}
+rm -f ${MNTFILE}
+
+if [ "${RES}" != "0" ]; then
+    echo "Failed to create '${NAME}'"
+    exit 1
+fi
+
+echo "Done."
+echo -e "\nYou can run your container with the 'lxc-start -n ${NAME}'\n"
+}
+
+destroy() {
+
+    echo -n "What is the name for the container ? [${NAME}] "
+    read _NAME_
+
+    if [ ! -z "${_NAME_}" ]; then
+	NAME=${_NAME_}
+    fi
+
+    @BINDIR@/lxc-destroy -n ${NAME}
+    RETVAL=$?
+    if [ ! ${RETVAL} -eq 0 ]; then
+	echo "Failed to destroyed '${NAME}'"
+	return ${RETVAL}
+    fi
+
+    ROOTFS="./rootfs.${NAME}"
+
+    echo -n "Shall I remove the rootfs [y/n] ? "
+    read
+    if [ "${REPLY}" = "y" ]; then
+	rm -rf ${ROOTFS}
+    fi
+
+    return 0
+}
+
+help() {
+    cat <<EOF
+
+This script is a helper to create ${DISTRO} system containers.
+
+The script will create the container configuration file following
+the informations submitted interactively with 'lxc-${DISTRO} create'
+
+The first creation will download, with yum, a ${DISTRO} minimal
+install and store it into a cache.
+
+The script will copy from the cache the root filesystem to the
+current directory.
+
+If there is a problem with the container, (bad configuration for
+example), you can destroy the container with 'lxc-${DISTRO} destroy'
+but without removing the rootfs and recreate it again with
+'lxc-${DISTRO} create'.
+
+If you want to create another ${DISTRO} container, call the 'lxc-${DISTRO}
+ create' again, specifying another name and new parameters.
+
+At any time you can purge the ${DISTRO} cache download by calling
+'lxc-${DISTRO} purge'
+
+Have fun :)
+
+EOF
+}
+
+purge() {
+
+    if [ ! -e ${CACHE} ]; then
+	exit 0
+    fi
+
+    # lock, so we won't purge while someone is creating a repository
+    (
+	flock -n -x 200
+
+	RES=$?
+	if [ "${RES}" != "0" ]; then
+	    echo "Cache repository is busy."
+	    exit 1
+	fi
+
+	echo -n "Purging the download cache..."
+	rm --preserve-root --one-file-system -rf ${CACHE} && echo "Done." || exit 1
+	exit 0
+
+    ) 200> "@LOCALSTATEDIR@/lock/subsys/lxc"
+}
+
+# Note: assuming uid==0 is root -- might break with userns??
+if [ "$(id -u)" != "0" ]; then
+	echo "This script should be run as 'root'"
+	exit 1
+fi
+
+# Detect which executable we were run as, lxc-fedora or lxc-redhat
+case "$0" in
+    *lxc-redhat)
+	DISTRO="redhat";;
+    *) # default is fedora
+	DISTRO="fedora";;
+esac
+CACHE="@LOCALSTATEDIR@/cache/lxc/${DISTRO}"
+
+case "$1" in
+    create)
+	create;;
+    destroy)
+	destroy;;
+    help)
+	help;;
+    purge)
+	purge;;
+    *)
+	echo "Usage: $0 {create|destroy|purge|help}"
+	exit 1;;
+esac




More information about the Containers mailing list