#!/bin/bash # set -ex DISTRO="fedora" CACHE="@LOCALSTATEDIR@/cache/lxc/${DISTRO}" # Default container name NAME="fedora" CONFFILE="lxc.conf" UTSNAME= IPV4="172.20.0.21" GATEWAY="172.20.0.1" MTU="1500" # 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 < ${ROOTFS}/${FSTAB} tmpfs /dev/shm tmpfs defaults 0 0 EOF } # custom inittab write_distro_inittab() { cat < ${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 < ${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 < ${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 MTU=${MTU} EOF } # custom hostname write_distro_hostname() { cat < ${ROOTFS}/etc/sysconfig/network NETWORKING=yes HOSTNAME=${UTSNAME} EOF } # custom sshd configuration file write_distro_sshd_config() { cat < ${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 < ${CONFFILE} lxc.utsname = ${UTSNAME} lxc.tty = 4 lxc.network.type = veth lxc.network.flags = up lxc.network.link = br0 lxc.network.name = eth0 lxc.network.mtu = ${MTU} 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 } 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 # choose the MTU size echo -n "What is the MTU size ? [$MTU] " read _MTU_ if [ ! -z "$_MTU_" ]; then MTU=$_MTU_ 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-${RELEASE}.noarch" RPM="rpm --root ${CACHE}/partial" echo "Initializing RPM cache ..." ${RPM} --initdb echo "Downloading distribution release file ${PKG}" yumdownloader --destdir="${CACHE}/partial" "${PKG}" RESULT=$? if [ "${RESULT}" != "0" ]; then echo "Enable to download the distribution release file" exit 1 fi ${RPM} --nodeps -ihv "${CACHE}/partial/${PKG}.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_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} 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 < "@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