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@xxxxxxxxxx> --- 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 + +@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 _______________________________________________ Containers mailing list Containers@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/containers