#!/bin/bash # # template script for generating suse container for LXC # # # lxc: linux Container library # Authors: # Daniel Lezcano # Frederic Crozat # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA DISTRO=11.4 configure_opensuse() { rootfs=$1 hostname=$2 # set network as static, but everything is done by LXC outside the container cat < $rootfs/etc/sysconfig/network/ifcfg-eth0 STARTMODE='auto' BOOTPROTO='static' EOF # set default route IP=$(/sbin/ip route | awk '/default/ { print $3 }') echo "default $IP - -" > $rootfs/etc/sysconfig/network/routes # create empty fstab touch $rootfs/etc/fstab # create minimal /dev mknod -m 666 $rootfs/dev/random c 1 8 mknod -m 666 $rootfs/dev/urandom c 1 9 mkdir -m 755 $rootfs/dev/pts mkdir -m 1777 $rootfs/dev/shm mknod -m 666 $rootfs/dev/tty c 5 0 mknod -m 600 $rootfs/dev/console c 5 1 mknod -m 666 $rootfs/dev/tty0 c 4 0 mknod -m 666 $rootfs/dev/tty1 c 4 1 mknod -m 666 $rootfs/dev/tty2 c 4 2 mknod -m 666 $rootfs/dev/tty3 c 4 3 mknod -m 666 $rootfs/dev/tty4 c 4 4 ln -s null $rootfs/dev/tty10 mknod -m 666 $rootfs/dev/full c 1 7 mknod -m 666 $rootfs/dev/ptmx c 5 2 ln -s /proc/self/fd $rootfs/dev/fd ln -s /proc/kcore $rootfs/dev/core mkdir -m 755 $rootfs/dev/mapper mknod -m 600 $rootfs/dev/mapper/control c 10 60 mkdir -m 755 $rootfs/dev/net mknod -m 666 $rootfs/dev/net/tun c 10 200 # set the hostname cat < $rootfs/etc/HOSTNAME $hostname EOF # do not use hostname from HOSTNAME variable cat <> $rootfs/etc/sysconfig/cron unset HOSTNAME EOF # set minimal hosts cat < $rootfs/etc/hosts 127.0.0.1 localhost $hostname EOF # disable various services # disable yast->bootloader in container cat < $rootfs/etc/sysconfig/bootloader LOADER_TYPE=none LOADER_LOCATION=none EOF # cut down inittab cat < $rootfs/etc/inittab id:3:initdefault: si::bootwait:/etc/init.d/boot 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 l6:6:wait:/etc/init.d/rc 6 ls:S:wait:/etc/init.d/rc S ~~:S:respawn:/sbin/sulogin p6::ctrlaltdel:/sbin/init 6 p0::powerfail:/sbin/init 0 cons:2345:respawn:/sbin/mingetty --noclear console screen c1:2345:respawn:/sbin/mingetty --noclear tty1 screen EOF # patch boot script, no longer needed in openSUSE 12.1 / SLE11-SP2 patch --quiet -d $rootfs/etc/init.d/ << EOF --- boot.orig 2011-05-26 16:03:07.000000000 +0200 +++ boot 2011-05-26 16:03:19.000000000 +0200 @@ -98,12 +98,12 @@ echo "***************************************************************" /sbin/halt -f fi - echo -n "Mounting devtmpfs at /dev" - mount -n -t devtmpfs -o mode=0755 devtmpfs /dev - rc_status -v -r +# echo -n "Mounting devtmpfs at /dev" +# mount -n -t devtmpfs -o mode=0755 devtmpfs /dev +# rc_status -v -r fi -cp -axT --remove-destination /lib/udev/devices /dev +#cp -axT --remove-destination /lib/udev/devices /dev if test -d /sys/kernel/debug -a "$HAVE_DEBUGFS" = "1" ; then mount -n -t debugfs debugfs /sys/kernel/debug > /dev/null 2>&1 EOF cat <> $rootfs/etc/sysconfig/boot # disable root fsck ROOTFS_FSCK="0" ROOTFS_BLKDEV="/dev/null" EOF # remove pointless services in a container insserv -r -f -p $rootfs/etc/init.d boot.udev boot.udev_retry boot.md boot.lvm boot.loadmodules boot.device-mapper boot.clock boot.swap boot.klog echo "Please change root-password !" echo "root:root" | chroot $rootfs chpasswd return 0 } download_opensuse() { cache=$1 arch=$2 # check the mini opensuse was not already downloaded mkdir -p "$cache/partial-$arch" if [ $? -ne 0 ]; then echo "Failed to create '$cache/partial-$arch' directory" return 1 fi # download a mini opensuse into a cache echo "Downloading opensuse minimal ..." mkdir -p "$cache/partial-$arch/dev" mknod -m 666 $cache/partial-$arch/dev/null c 1 3 mknod -m 666 $cache/partial-$arch/dev/zero c 1 5 zypper --quiet --root $cache/partial-$arch --non-interactive ar http://download.opensuse.org/distribution/$DISTRO/repo/oss/ repo-oss zypper --quiet --root $cache/partial-$arch --non-interactive ar http://download.opensuse.org/update/$DISTRO/ update zypper --quiet --root $cache/partial-$arch --non-interactive --gpg-auto-import-keys in --auto-agree-with-licenses -t pattern base zypper --quiet --root $cache/partial-$arch --non-interactive --gpg-auto-import-keys in +lxc -kbd -patterns-openSUSE-base if [ $? -ne 0 ]; then echo "Failed to download the rootfs, aborting." return 1 fi mv "$1/partial-$arch" "$1/rootfs-$arch" echo "Download complete." return 0 } copy_opensuse() { cache=$1 arch=$2 rootfs=$3 # make a local copy of the mini opensuse echo -n "Copying rootfs to $rootfs ..." mkdir -p $rootfs rsync -a $cache/rootfs-$arch/ $rootfs/ || return 1 return 0 } install_opensuse() { cache="/var/cache/lxc/opensuse" rootfs=$1 mkdir -p /var/lock/subsys/ ( flock -x 200 if [ $? -ne 0 ]; then echo "Cache repository is busy." return 1 fi arch=$(arch) echo "Checking cache download in $cache/rootfs-$arch ... " if [ ! -e "$cache/rootfs-$arch" ]; then download_opensuse $cache $arch if [ $? -ne 0 ]; then echo "Failed to download 'opensuse base'" return 1 fi fi echo "Copy $cache/rootfs-$arch to $rootfs ... " copy_opensuse $cache $arch $rootfs if [ $? -ne 0 ]; then echo "Failed to copy rootfs" return 1 fi return 0 ) 200>/var/lock/subsys/lxc return $? } copy_configuration() { path=$1 rootfs=$2 name=$3 cat <> $path/config lxc.utsname = $name lxc.tty = 4 lxc.pts = 1024 lxc.rootfs = $rootfs lxc.mount = $path/fstab # uncomment the next line to run the container unconfined: #lxc.aa_profile = unconfined 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 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 cat < $path/fstab proc proc proc nodev,noexec,nosuid 0 0 sysfs sys sysfs defaults 0 0 EOF if [ $? -ne 0 ]; then echo "Failed to add configuration" return 1 fi return 0 } clean() { cache="/var/cache/lxc/opensuse" if [ ! -e $cache ]; then exit 0 fi # lock, so we won't purge while someone is creating a repository ( flock -x 200 if [ $? != 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>/var/lock/subsys/lxc } usage() { cat < --clean EOF return 0 } options=$(getopt -o hp:n:c -l help,path:,name:,clean -- "$@") if [ $? -ne 0 ]; then usage $(basename $0) exit 1 fi eval set -- "$options" while true do case "$1" in -h|--help) usage $0 && exit 0;; -p|--path) path=$2; shift 2;; -n|--name) name=$2; shift 2;; -c|--clean) clean=$2; shift 2;; --) shift 1; break ;; *) break ;; esac done if [ ! -z "$clean" -a -z "$path" ]; then clean || exit 1 exit 0 fi type zypper > /dev/null if [ $? -ne 0 ]; then echo "'zypper' command is missing" exit 1 fi if [ -z "$path" ]; then echo "'path' parameter is required" exit 1 fi if [ "$(id -u)" != "0" ]; then echo "This script should be run as 'root'" exit 1 fi rootfs=$path/rootfs install_opensuse $rootfs if [ $? -ne 0 ]; then echo "failed to install opensuse" exit 1 fi configure_opensuse $rootfs $name if [ $? -ne 0 ]; then echo "failed to configure opensuse for a container" exit 1 fi copy_configuration $path $rootfs $name if [ $? -ne 0 ]; then echo "failed write configuration file" exit 1 fi if [ ! -z $clean ]; then clean || exit 1 exit 0 fi