From: mitty Date: Tue, 16 Oct 2012 05:35:18 +0000 (+0000) Subject: * /usr/lib/lxc/templates of lxc 0.8.0~rc1-4ubuntu37 on Ubuntu 12.10 (beta) X-Git-Url: http://lab.mitty.jp/git/?p=lab.git;a=commitdiff_plain;h=88df158a61b549312e9a380cfea2ba8a94f73e18 * /usr/lib/lxc/templates of lxc 0.8.0~rc1-4ubuntu37 on Ubuntu 12.10 (beta) git-svn-id: https://lab.mitty.jp/svn/lab/vendor@175 7d2118f6-f56c-43e7-95a2-4bb3031d96e7 --- diff --git a/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-altlinux b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-altlinux new file mode 100755 index 0000000..90506e6 --- /dev/null +++ b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-altlinux @@ -0,0 +1,460 @@ +#!/bin/bash + +# +# template script for generating altlinux container for LXC +# + +# +# lxc: linux Container library + +# Authors: +# Alexey Shabalin + +# 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 + +#Configurations +arch=$(arch) +cache_base=/var/cache/lxc/altlinux/$arch +default_path=${localstatedir}/lib/lxc +default_profile=default +profile_dir=/etc/lxc/profiles +root_password=rooter +lxc_network_type=veth +lxc_network_link=virbr0 + +# is this altlinux? +[ -f /etc/altlinux-release ] && is_altlinux=true + +configure_altlinux() +{ + + # disable selinux in altlinux + mkdir -p $rootfs_path/selinux + echo 0 > $rootfs_path/selinux/enforce + + mkdir -p ${rootfs_path}/etc/net/ifaces/veth0 + cat < ${rootfs_path}/etc/net/ifaces/veth0/options +BOOTPROTO=${BOOTPROTO} +ONBOOT=yes +NM_CONTROLLED=no +TYPE=eth +EOF + +if [ ${BOOTPROTO} != "dhcp" ]; then + # ip address + cat < ${rootfs_path}/etc/net/ifaces/veth0/ipv4address +${ipv4} +EOF + + cat < ${rootfs_path}/etc/net/ifaces/veth0/ipv4route +${gw} +EOF + + cat < ${rootfs_path}/etc/net/ifaces/veth0/resolv.conf +nameserver ${dns} +EOF + + cat < ${rootfs_path}/etc/net/ifaces/veth0/ipv6address +${ipv6} +EOF + + cat < ${rootfs_path}/etc/net/ifaces/veth0/ipv6route +${gw6} +EOF + +fi + + # set the hostname + cat < ${rootfs_path}/etc/sysconfig/network +NETWORKING=yes +CONFMETHOD=etcnet +HOSTNAME=${UTSNAME} +RESOLV_MODS=yes +EOF + + # set minimal hosts + cat < $rootfs_path/etc/hosts +127.0.0.1 localhost.localdomain localhost $name +EOF + # Allow to login at virsh console. loginuid.so doen't work in the absence of auditd. +# sed -i 's/^.*loginuid.so.*$/\#&/' ${rootfs_path}/etc/pam.d/common-login + + # Allow root to login at virsh console + echo "pts/0" >> ${rootfs_path}/etc/securetty + echo "console" >> ${rootfs_path}/etc/securetty + + chroot ${rootfs_path} chkconfig network on + chroot ${rootfs_path} chkconfig syslogd on + chroot ${rootfs_path} chkconfig random on + chroot ${rootfs_path} chkconfig rawdevices off + chroot ${rootfs_path} chkconfig fbsetfont off +# chroot ${rootfs_path} chkconfig keytable off + + subst 's/^\([3-9]\+:[0-9]\+:respawn:\/sbin\/mingetty.*\)/#\1/' ${rootfs_path}/etc/inittab + echo "c1:2345:respawn:/sbin/mingetty --noclear console" >> ${rootfs_path}/etc/inittab + subst 's,\/dev\/tty12,/var/log/syslog/console,' ${rootfs_path}/etc/syslog.conf + +# touch file for fastboot + touch ${rootfs_path}/fastboot + chattr +i ${rootfs_path}/fastboot + + dev_path="${rootfs_path}/dev" + rm -rf ${dev_path} + mkdir -p ${dev_path} + mknod -m 666 ${dev_path}/null c 1 3 + mknod -m 666 ${dev_path}/zero c 1 5 + mknod -m 644 ${dev_path}/random c 1 8 + mknod -m 644 ${dev_path}/urandom c 1 9 + mkdir -m 755 ${dev_path}/pts + mkdir -m 1777 ${dev_path}/shm + mknod -m 666 ${dev_path}/tty c 5 0 + chown root:tty ${dev_path}/tty + mknod -m 600 ${dev_path}/tty0 c 4 0 + mknod -m 600 ${dev_path}/tty1 c 4 1 + mknod -m 600 ${dev_path}/tty2 c 4 2 + mknod -m 600 ${dev_path}/tty3 c 4 3 + mknod -m 600 ${dev_path}/tty4 c 4 4 + mknod -m 600 ${dev_path}/console c 5 1 + mknod -m 666 ${dev_path}/full c 1 7 + mknod -m 600 ${dev_path}/initctl p + mknod -m 666 ${dev_path}/ptmx c 5 2 + chown root:tty ${dev_path}/ptmx + ln -s /proc/self/fd ${dev_path}/fd + ln -s /proc/kcore ${dev_path}/core + mkdir -m 755 ${dev_path}/mapper + mknod -m 600 ${dev_path}/mapper/control c 10 236 + mkdir -m 755 ${dev_path}/net + mknod -m 666 ${dev_path}/net/tun c 10 200 + + echo "setting root passwd to $root_password" + echo "root:$root_password" | chroot $rootfs_path chpasswd + + return 0 +} + +download_altlinux() +{ + + # check the mini altlinux was not already downloaded + INSTALL_ROOT=$cache/partial + mkdir -p $INSTALL_ROOT + if [ $? -ne 0 ]; then + echo "Failed to create '$INSTALL_ROOT' directory" + return 1 + fi + + # download a mini altlinux into a cache + echo "Downloading altlinux minimal ..." + APT_GET="apt-get -o RPM::RootDir=$INSTALL_ROOT -y" + PKG_LIST="$(grep -hs '^[^#]' "$profile_dir/$profile")" +# PKG_LIST="basesystem apt apt-conf-sisyphus etcnet openssh-server passwd sysklogd net-tools e2fsprogs" + + mkdir -p $INSTALL_ROOT/var/lib/rpm + rpm --root $INSTALL_ROOT --initdb + $APT_GET install $PKG_LIST + + if [ $? -ne 0 ]; then + echo "Failed to download the rootfs, aborting." + return 1 + fi + + mv "$INSTALL_ROOT" "$cache/rootfs" + echo "Download complete." + + return 0 +} + +copy_altlinux() +{ + + # make a local copy of the minialtlinux + echo -n "Copying rootfs to $rootfs_path ..." + #cp -a $cache/rootfs-$arch $rootfs_path || return 1 + # i prefer rsync (no reason really) + mkdir -p $rootfs_path + rsync -a $cache/rootfs/ $rootfs_path/ + return 0 +} + +update_altlinux() +{ + chroot $cache/rootfs apt-get update + chroot $cache/rootfs apt-get -y dist-upgrade +} + +install_altlinux() +{ + mkdir -p /var/lock/subsys/ + ( + flock -x 200 + if [ $? -ne 0 ]; then + echo "Cache repository is busy." + return 1 + fi + + echo "Checking cache download in $cache/rootfs ... " + if [ ! -e "$cache/rootfs" ]; then + download_altlinux + if [ $? -ne 0 ]; then + echo "Failed to download 'altlinux base'" + return 1 + fi + else + echo "Cache found. Updating..." + update_altlinux + if [ $? -ne 0 ]; then + echo "Failed to update 'altlinux base', continuing with last known good cache" + else + echo "Update finished" + fi + fi + + echo "Copy $cache/rootfs to $rootfs_path ... " + copy_altlinux + if [ $? -ne 0 ]; then + echo "Failed to copy rootfs" + return 1 + fi + + return 0 + + ) 200>/var/lock/subsys/lxc + + return $? +} + +copy_configuration() +{ + + mkdir -p $config_path + grep -q "^lxc.rootfs" $config_path/config 2>/dev/null || echo "lxc.rootfs = $rootfs_path" >> $config_path/config + cat <> $config_path/config +lxc.utsname = $name +lxc.tty = 4 +lxc.pts = 1024 +lxc.mount = $config_path/fstab +#networking +lxc.network.type = $lxc_network_type +lxc.network.flags = up +lxc.network.link = $lxc_network_link +lxc.network.name = veth0 +lxc.network.mtu = 1500 +EOF +if [ ! -z ${ipv4} ]; then + cat <> $config_path/config +lxc.network.ipv4 = $ipv4 +EOF +fi +if [ ! -z ${gw} ]; then + cat <> $config_path/config +lxc.network.ipv4.gateway = $gw +EOF +fi +if [ ! -z ${ipv6} ]; then + cat <> $config_path/config +lxc.network.ipv6 = $ipv6 +EOF +fi +if [ ! -z ${gw6} ]; then + cat <> $config_path/config +lxc.network.ipv6.gateway = $gw6 +EOF +fi + cat <> $config_path/config +#cgroups +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 10:135 rwm +EOF + + cat < $config_path/fstab +proc $rootfs_path/proc proc nodev,noexec,nosuid 0 0 +sysfs $rootfs_path/sys sysfs defaults 0 0 +EOF + + if [ $? -ne 0 ]; then + echo "Failed to add configuration" + return 1 + fi + + return 0 +} + +clean() +{ + + if [ ! -e $cache ]; then + exit 0 + fi + + # lock, so we won't purge while someone is creating a repository + ( + flock -n -x 200 + if [ $? != 0 ]; then + echo "Cache repository is busy." + exit 1 + fi + + echo -n "Purging the download cache for ALTLinux-$release..." + rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1 + exit 0 + + ) 200>/var/lock/subsys/lxc +} + +usage() +{ + cat < + [-p|--path=] [-c|--clean] [-R|--release=] + [-4|--ipv4=] [-6|--ipv6=] + [-g|--gw=] [-d|--dns=] + [-P|--profile=] + [-A|--arch=] + [-h|--help] +Mandatory args: + -n,--name container name, used to as an identifier for that container from now on +Optional args: + -p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc. The container config will go under /var/lib/lxc in and case + -c,--clean clean the cache + -R,--release ALTLinux release for the new container. if the host is ALTLinux, then it will defaultto the host's release. + -4,--ipv4 specify the ipv4 address to assign to the virtualized interface, eg. 192.168.1.123/24 + -6,--ipv6 specify the ipv6 address to assign to the virtualized interface, eg. 2003:db8:1:0:214:1234:fe0b:3596/64 + -g,--gw specify the default gw, eg. 192.168.1.1 + -G,--gw6 specify the default gw, eg. 2003:db8:1:0:214:1234:fe0b:3596 + -d,--dns specify the DNS server, eg. 192.168.1.2 + -P,--profile Profile name is the file name in /etc/lxc/profiles contained packages name for install to cache. + -A,--arch NOT USED YET. Define what arch the container will be [i686,x86_64] + -h,--help print this help +EOF + return 0 +} + +options=$(getopt -o hp:n:P:cR:4:6:g:d: -l help,path:,name:,profile:,clean,release:ipv4:ipv6:gw:dns: -- "$@") +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;; + -P|--profile) profile=$2; shift 2;; + -c|--clean) clean=$2; shift 2;; + -R|--release) release=$2; shift 2;; + -4|--ipv4) ipv4=$2; shift 2;; + -6|--ipv6) ipv6=$2; shift 2;; + -g|--gw) gw=$2; shift 2;; + -d|--dns) dns=$2; shift 2;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ ! -z "$clean" -a -z "$path" ]; then + clean || exit 1 + exit 0 +fi + +type apt-get >/dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "'apt-get' command is missing" + exit 1 +fi + +if [ -z "$path" ]; then + path=$default_path +fi + +if [ -z "$profile" ]; then + profile=$default_profile +fi + +if [ -z "$release" ]; then + if [ "$is_altlinux" ]; then + release=$(cat /etc/altlinux-release |awk '/^ALT/ {print $3}') + else + echo "This is not a ALTLinux host and release missing, use -R|--release to specify release" + exit 1 + fi +fi + +if [ -z "$ipv4" -a -z "$ipv6" ]; then + BOOTPROTO="dhcp" +else + BOOTPROTO="static" +fi + +if [ "$(id -u)" != "0" ]; then + echo "This script should be run as 'root'" + exit 1 +fi + +rootfs_path=$path/$name/rootfs +config_path=$default_path/$name +cache=$cache_base/$release/$profile + +if [ -f $config_path/config ]; then + echo "A container with that name exists, chose a different name" + exit 1 +fi + +# check for 'lxc.rootfs' passed in through default config by lxc-create +if grep -q '^lxc.rootfs' $path/config 2>/dev/null ; then + rootfs_path=`grep 'lxc.rootfs =' $path/config | awk -F= '{ print $2 }'` +fi + +install_altlinux +if [ $? -ne 0 ]; then + echo "failed to install altlinux" + exit 1 +fi + +configure_altlinux +if [ $? -ne 0 ]; then + echo "failed to configure altlinux for a container" + exit 1 +fi + +copy_configuration +if [ $? -ne 0 ]; then + echo "failed write configuration file" + exit 1 +fi + +if [ ! -z $clean ]; then + clean || exit 1 + exit 0 +fi +echo "container rootfs and config created" +echo "container is configured for lxc.network.type=veth and lxc.network.link=virbr0 (which is default if you have libvirt runnig)" diff --git a/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-archlinux b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-archlinux new file mode 100755 index 0000000..d5a8fb6 --- /dev/null +++ b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-archlinux @@ -0,0 +1,466 @@ +#!/bin/bash + +# +# template script for generating Arch linux container for LXC +# + +# +# lxc: linux Container library + +# Authors: +# Alexander Vladimirov + +# 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 + +# defaults +arch=$(arch) +cache=/var/cache/lxc/arch/${arch} +lxc_network_type="veth" +lxc_network_link="br0" +default_path=/var/lib/lxc +default_rc_locale="en-US.UTF-8" +default_rc_timezone="UTC" +host_mirror="http://mirrors.kernel.org/archlinux/\$repo/os/$arch" + +# sort of minimal package set +base_packages=( + "filesystem" + "initscripts" + "coreutils" + "module-init-tools" + "procps" + "psmisc" + "pacman" + "bash" + "syslog-ng" + "cronie" + "iproute2" + "iputils" + "inetutils" + "dhcpcd" + "dnsutils" + "nano" + "grep" + "less" + "gawk" + "sed" + "tar" + "wget" + "gzip" + "which" +) +declare -a additional_packages + +[ -f /etc/arch-release ] && is_arch=true + +# find and extract parameter value from given config file +# ${1} - file to read parameter from +# ${2} - parameter name +# ${result} - result value on success +function read_parameter_value { + [ -f ${1} ] && [ "${2}" ] || return 1 + local pattern="^[[:space:]]*${2}[[:space:]]*=[[:space:]]*" + local str=$(grep "${pattern}" "${1}") + local str=${str/#$(grep -o "${pattern}" "${1}")/} + result=${str//\"/} + return 0 +} + +# split comma-separated string into an array +# ${1} - string to split +# ${2} - separator (default is ",") +# ${result} - result value on success +function split_string { + local ifs=${IFS} + IFS="${2:-,}" + read -a result < <(echo "${1}") + IFS=${ifs} + return 0 +} + +# Arch-specific preconfiguration for container +function configure_arch { + # read locale and timezone defaults from system rc.conf if running on Arch + if [ "${is_arch}" ]; then + read_parameter_value "/etc/rc.conf" "LOCALE" + rc_locale=${result:-${default_rc_locale}} + read_parameter_value "/etc/rc.conf" "TIMEZONE" + rc_timezone=${result:-${default_rc_timezone}} + else + rc_locale=${default_rc_locale} + rc_timezone=${default_rc_timezone} + fi + + echo "Setting up rc.conf" + cat > "${rootfs_path}/etc/rc.conf" << EOF +# /etc/rc.conf - Main Configuration for Arch Linux +LOCALE="${rc_locale}" +DAEMON_LOCALE="no" +HARDWARECLOCK="local" +TIMEZONE="${rc_timezone}" +KEYMAP=us +CONSOLEFONT= +CONSOLEMAP= +USECOLOR="yes" +MODULES=() +HOSTNAME="${name}" +interface=eth0 +address= +netmask= +broadcast= +gateway= +DAEMONS=(syslog-ng crond network) +EOF + + if [ -e "${rootfs_path}/etc/locale.gen" ]; then + sed -i 's@^#\(en_US\.UTF-8\)@\1@' "${rootfs_path}/etc/locale.gen" + if [ ! "${rc_locale}" = "en_US.UTF-8" ]; then + echo "${rc_locale} ${rc_locale##*.}" >> "${rootfs_path}/etc/locale.gen" + fi + chroot "${rootfs_path}" locale-gen + fi + cp "${rootfs_path}/usr/share/zoneinfo/${rc_timezone}" \ + "${rootfs_path}/etc/localtime" + + echo "Setting up rc.sysinit" + cat > "${rootfs_path}/etc/rc.sysinit.lxc" << EOF +#!/bin/bash +. /etc/rc.conf +. /etc/rc.d/functions + +echo "starting Arch Linux" +rm -f \$(find /var/run -name '*pid') +rm -f /run/daemons/* +rm -f /var/lock/subsys/* +rm -f /etc/mtab +touch /etc/mtab +run_hook sysinit_end +EOF + + echo "Setting up rc.shutdown" + cat > "${rootfs_path}/etc/rc.shutdown.lxc" << EOF +#!/bin/bash +. /etc/rc.conf +. /etc/rc.d/functions +stty onlcr +run_hook shutdown_start +[[ -x /etc/rc.local.shutdown ]] && /etc/rc.local.shutdown +stop_all_daemons +run_hook shutdown_prekillall +kill_all +run_hook shutdown_postkillall +[[ \${TIMEZONE} ]] && cp --remove-destination "/usr/share/zoneinfo/\${TIMEZONE}" /etc/localtime +halt -w +umount -a -r -t nodevtmpfs,notmpfs,nosysfs,noproc,nodevpts -O no_netdev +run_hook shutdown_postumount +run_hook shutdown_poweroff +if [[ \${RUNLEVEL} = 0 ]]; then + poweroff -d -f -i +else + reboot -d -f -i +fi +# vim: set ts=2 sw=2 noet: +EOF + chmod 755 "${rootfs_path}/etc/rc.shutdown.lxc" "${rootfs_path}/etc/rc.sysinit.lxc" + + echo "Setting up inittab" + cat > "${rootfs_path}/etc/inittab" << EOF +id:3:initdefault: +rc::sysinit:/etc/rc.sysinit.lxc +rs:S1:wait:/etc/rc.single +rm:2345:wait:/etc/rc.multi +rh:06:wait:/etc/rc.shutdown.lxc +su:S:wait:/sbin/sulogin -p +c1:2345:respawn:/sbin/agetty -8 38400 tty1 linux +EOF + + echo "Setting up hosts" + cat > "${rootfs_path}/etc/hosts" << EOF +127.0.0.1 localhost.localdomain localhost ${name} +::1 localhost.localdomain localhost +EOF + + echo "Setting up nameserver" + grep nameserver /etc/resolv.conf > "${rootfs_path}/etc/resolv.conf" + + echo "Setting up device nodes" + mkdir -m 755 "${rootfs_path}/dev/pts" + mkdir -m 1777 "${rootfs_path}/dev/shm" + mknod -m 666 "${rootfs_path}/dev/null" c 1 3 + mknod -m 666 "${rootfs_path}/dev/full" c 1 7 + mknod -m 666 "${rootfs_path}/dev/random" c 1 8 + mknod -m 666 "${rootfs_path}/dev/urandom" c 1 9 + mknod -m 666 "${rootfs_path}/dev/tty0" c 4 0 + mknod -m 666 "${rootfs_path}/dev/tty1" c 4 1 + mknod -m 666 "${rootfs_path}/dev/tty2" c 4 2 + mknod -m 666 "${rootfs_path}/dev/tty3" c 4 3 + mknod -m 666 "${rootfs_path}/dev/tty4" c 4 4 + mknod -m 600 "${rootfs_path}/dev/initctl" p + mknod -m 666 "${rootfs_path}/dev/tty" c 5 0 + mknod -m 666 "${rootfs_path}/dev/console" c 5 1 + mknod -m 666 "${rootfs_path}/dev/ptmx" c 5 2 + + return 0 +} + +# write container configuration files +function copy_configuration { + mkdir -p "${config_path}" + grep -q "^lxc.rootfs" "${config_path}/config" 2>/dev/null || echo "lxc.rootfs=${rootfs_path}" >> "${config_path}/config" + cat > "${config_path}/config" << EOF +lxc.utsname=${name} +lxc.tty=4 +lxc.pts=1024 +lxc.mount=${config_path}/fstab +#networking +lxc.network.type=${lxc_network_type} +lxc.network.flags=up +lxc.network.link=${lxc_network_link} +lxc.network.name=eth0 +lxc.network.mtu=1500 +#cgroups +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 +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 > "${config_path}/fstab" << EOF +none ${rootfs_path}/dev/pts devpts defaults 0 0 +none ${rootfs_path}/proc proc nodev,noexec,nosuid 0 0 +none ${rootfs_path}/sys sysfs defaults 0 0 +none ${rootfs_path}/dev/shm tmpfs defaults 0 0 +EOF + + if [ ${?} -ne 0 ]; then + echo "Failed to configure container" + return 1 + fi + + return 0 +} + +# lock chroot and mount subdirectories before installing container +function mount_chroot { + echo "mounting chroot" + umask 0022 + [ -e "${rootfs_path}/sys" ] || mkdir "${rootfs_path}/sys" + mount -t sysfs sysfs "${rootfs_path}/sys" + [ -e "${rootfs_path}/proc" ] || mkdir "${rootfs_path}/proc" + mount -t proc proc "${rootfs_path}/proc" + [ -e "${rootfs_path}/dev" ] || mkdir "${rootfs_path}/dev" + mount -t tmpfs dev "${rootfs_path}/dev" -o mode=0755,size=10M,nosuid + mknod -m 666 "${rootfs_path}/dev/null" c 1 3 + mknod -m 666 "${rootfs_path}/dev/zero" c 1 5 + mknod -m 600 "${rootfs_path}/dev/console" c 5 1 + mknod -m 644 "${rootfs_path}/dev/random" c 1 8 + mknod -m 644 "${rootfs_path}/dev/urandom" c 1 9 + mknod -m 666 "${rootfs_path}/dev/tty" c 5 0 + mknod -m 666 "${rootfs_path}/dev/tty0" c 4 0 + mknod -m 666 "${rootfs_path}/dev/full" c 1 7 + ln -s /proc/kcore "${rootfs_path}/dev/core" + ln -s /proc/self/fd "${rootfs_path}/dev/fd" + ln -s /proc/self/fd/0 "${rootfs_path}/dev/stdin" + ln -s /proc/self/fd/1 "${rootfs_path}/dev/stdout" + ln -s /proc/self/fd/2 "${rootfs_path}/dev/stderr" + [ -e "${rootfs_path}/dev/shm" ] || mkdir "${rootfs_path}/dev/shm" + mount -t tmpfs shm "${rootfs_path}/dev/shm" -o nodev,nosuid,size=128M + [ -e "${rootfs_path}/dev/pts" ] || mkdir "${rootfs_path}/dev/pts" + mount -t devpts devpts "${rootfs_path}/dev/pts" -o newinstance,ptmxmode=666 + ln -s pts/ptmx "${rootfs_path}/dev/ptmx" + [ -e "${cache_dir}" ] || mkdir -p "${cache_dir}" + [ -e "${rootfs_path}/${cache_dir}" ] || mkdir -p "${rootfs_path}/${cache_dir}" + mount -o bind "${cache_dir}" "${rootfs_path}/${cache_dir}" + if [ -n "${host_mirror_path}" ]; then + [ -e "${rootfs_path}/${host_mirror_path}" ] || mkdir -p "${rootfs_path}/${host_mirror_path}" + mount -o bind "${host_mirror_path}" "${rootfs_path}/${host_mirror_path}" + mount -o remount,ro,bind "${host_mirror_path}" "${rootfs_path}/${host_mirror_path}" + fi + trap 'umount_chroot' EXIT INT QUIT TERM HUP +} + +function umount_chroot { + if [ -z "${umount_done}" ]; then + echo "unmounting chroot" + umount "${rootfs_path}/proc" + umount "${rootfs_path}/sys" + umount "${rootfs_path}/dev/pts" + umount "${rootfs_path}/dev/shm" + umount "${rootfs_path}/dev" + umount "${rootfs_path}/${cache_dir}" + [ -n "${host_mirror_path}" ] && umount "${rootfs_path}/${host_mirror_path}" + umount_done=1 + fi +} + +# install packages within container chroot +function install_arch { + pacman_config=$(mktemp) + + cat < "${pacman_config}" +[options] +HoldPkg = pacman glibc +SyncFirst = pacman +Architecture = auto +#IgnorePkg = udev +[core] +Include = /etc/pacman.d/mirrorlist +Server = ${host_mirror} +[extra] +Include = /etc/pacman.d/mirrorlist +Server = ${host_mirror} +[community] +Include = /etc/pacman.d/mirrorlist +Server = ${host_mirror} +EOF + + mkdir -p "${rootfs_path}/var/lib/pacman/sync" + mkdir -p "${rootfs_path}/etc" + + if echo "${host_mirror}" | grep -q 'file://'; then + host_mirror_path=$(echo "${host_mirror}" | sed -E 's#file://(/.*)/\$repo/os/\$arch#\1#g') + fi + cache_dir=$( (grep -m 1 '^CacheDir' "${pacman_config}" || echo 'CacheDir = /var/cache/pacman/pkg') | sed 's/CacheDir\s*=\s*//') + mount_chroot + params="--root ${rootfs_path} --config=${pacman_config} --noconfirm" + if ! pacman -Sydd ${params} --dbonly udev; then + echo "Failed to preinstall udev package record" + return 1 + fi + if ! pacman -S ${params} ${base_packages[@]}; then + echo "Failed to install container packages" + return 1 + fi + [ -d "${rootfs_path}/lib/modules" ] && ldconfig -r "${rootfs_path}" + mv "${pacman_config}" "${rootfs_path}/etc/pacman.conf" + umount_chroot + return 0 +} + +usage() +{ + cat < + [-P|--packages=] [-p|--path=] [-h|--help] +Mandatory args: + -n,--name container name, used to as an identifier for that container from now on +Optional args: + -p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc. The container config will go under /var/lib/lxc in that case + -P,--packages preinstall additional packages, comma-separated list + -h,--help print this help +EOF + return 0 +} + +options=$(getopt -o hp:P:n:cm: -l help,path:,packages:,name:,clean,mirror: -- "${@}") +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;; + -P|--packages) additional_packages=${2}; shift 2;; + -m|--mirror) host_mirror=${2}; shift 2;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ -z "${name}" ]; then + echo "missing required 'name' parameter" + exit 1 +fi + +type pacman >/dev/null 2>&1 +if [ ${?} -ne 0 ]; then + echo "'pacman' command is missing, refer to wiki.archlinux.org for information about installing pacman" + exit 1 +fi + +if [ -z "${path}" ]; then + path="${default_path}/${name}" +fi + +if [ "${EUID}" != "0" ]; then + echo "This script should be run as 'root'" + exit 1 +fi + +rootfs_path="${path}/rootfs" +# check for 'lxc.rootfs' passed in through default config by lxc-create +if grep -q '^lxc.rootfs' $path/config 2>/dev/null ; then + rootfs_path=`grep 'lxc.rootfs =' $path/config | awk -F= '{ print $2 }'` +fi +config_path="${default_path}/${name}" + +revert() +{ + echo "Interrupted, so cleaning up" + lxc-destroy -n "${name}" + # maybe was interrupted before copy config + rm -rf "${path}/${name}" + rm -rf "${default_path}/${name}" + exit 1 +} + +trap revert SIGHUP SIGINT SIGTERM + +copy_configuration +if [ ${?} -ne 0 ]; then + echo "failed write configuration file" + rm -rf "${config_path}" + exit 1 +fi + +if [ ${#additional_packages[@]} -gt 0 ]; then + split_string ${additional_packages} + base_packages+=(${result[@]}) +fi + +install_arch +if [ ${?} -ne 0 ]; then + echo "failed to install Arch linux" + rm -rf "${config_path}" "${path}" + exit 1 +fi + +configure_arch +if [ ${?} -ne 0 ]; then + echo "failed to configure Arch linux for a container" + rm -rf "${config_path}" "${path}" + exit 1 +fi + +echo "container rootfs and config created" diff --git a/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-busybox b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-busybox new file mode 100755 index 0000000..1314b9e --- /dev/null +++ b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-busybox @@ -0,0 +1,320 @@ +#!/bin/bash + +# +# lxc: linux Container library + +# Authors: +# Daniel Lezcano + +# 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 + +install_busybox() +{ + rootfs=$1 + name=$2 + res=0 + tree="\ +$rootfs/selinux \ +$rootfs/dev \ +$rootfs/home \ +$rootfs/root \ +$rootfs/etc \ +$rootfs/etc/init.d \ +$rootfs/bin \ +$rootfs/sbin \ +$rootfs/proc \ +$rootfs/mnt \ +$rootfs/tmp \ +$rootfs/var/log \ +$rootfs/usr/share/udhcpc \ +$rootfs/dev/pts \ +$rootfs/dev/shm \ +$rootfs/lib \ +$rootfs/usr/lib \ +$rootfs/lib64 \ +$rootfs/usr/lib64" + + mkdir -p $tree || return 1 + chmod 755 $tree || return 1 + + pushd $rootfs/dev > /dev/null || return 1 + + # minimal devices needed for busybox + mknod tty c 5 0 || res=1 + mknod console c 5 1 || res=1 + chmod 666 tty console || res=1 + mknod tty0 c 4 0 || res=1 + mknod tty1 c 4 0 || res=1 + mknod tty5 c 4 0 || res=1 + chmod 666 tty0 || res=1 + mknod ram0 b 1 0 || res=1 + chmod 600 ram0 || res=1 + mknod null c 1 3 || res=1 + chmod 666 null || res=1 + + popd > /dev/null + + # root user defined + cat <> $rootfs/etc/passwd +root:x:0:0:root:/root:/bin/sh +EOF + + cat <> $rootfs/etc/group +root:x:0:root +EOF + + # mount everything + cat <> $rootfs/etc/init.d/rcS +#!/bin/sh +/bin/syslogd +/bin/mount -a +/bin/udhcpc +EOF + + # executable + chmod 744 $rootfs/etc/init.d/rcS || return 1 + + # mount points + cat <> $rootfs/etc/fstab +proc /proc proc defaults 0 0 +shm /dev/shm tmpfs defaults 0 0 +EOF + + # writable and readable for other + chmod 644 $rootfs/etc/fstab || return 1 + + # launch rcS first then make a console available + # and propose a shell on the tty, the last one is + # not needed + cat <> $rootfs/etc/inittab +::sysinit:/etc/init.d/rcS +tty1::respawn:/bin/getty -L tty1 115200 vt100 +console::askfirst:/bin/sh +EOF + # writable and readable for other + chmod 644 $rootfs/etc/inittab || return 1 + + cat <> $rootfs/usr/share/udhcpc/default.script +#!/bin/sh + +case "\$1" in + deconfig) + ip addr flush dev \$interface + ;; + + renew|bound) + + # flush all the routes + if [ -n "\$router" ]; then + ip route del default 2> /dev/null + fi + + # check broadcast + if [ -n "\$broadcast" ]; then + broadcast="broadcast \$broadcast" + fi + + # add a new ip address + ip addr add \$ip/\$mask \$broadcast dev \$interface + + if [ -n "\$router" ]; then + ip route add default via \$router dev \$interface + fi + + [ -n "\$domain" ] && echo search \$domain > /etc/resolv.conf + for i in \$dns ; do + echo nameserver \$i >> /etc/resolv.conf + done + ;; +esac +exit 0 +EOF + + chmod 744 $rootfs/usr/share/udhcpc/default.script + + return $res +} + +configure_busybox() +{ + rootfs=$1 + + functions="\ + [ [[ addgroup adduser adjtimex ar arp arping ash awk basename \ + brctl bunzip2 bzcat bzip2 cal cat catv chattr chgrp chmod \ + chown chpasswd chpst chroot chrt chvt cksum clear cmp comm \ + cp cpio crond crontab cryptpw cut date dc dd deallocvt \ + delgroup deluser df dhcprelay diff dirname dmesg dnsd dos2unix \ + du dumpkmap dumpleases echo ed egrep eject env envdir envuidgid \ + ether-wake expand expr fakeidentd false fbset fdformat fdisk \ + fetchmail fgrep find findfs fold free freeramdisk fsck \ + fsck.minix ftpget ftpput fuser getopt getty grep gunzip gzip \ + halt hdparm head hexdump hostid hostname httpd hwclock id \ + ifconfig ifdown ifenslave ifup inetd init insmod install ip \ + ipaddr ipcalc ipcrm ipcs iplink iproute iprule iptunnel \ + kbd_mode kill killall killall5 klogd last length less linux32 \ + linux64 linuxrc ln loadfont loadkmap logger login logname \ + logread losetup lpd lpq lpr ls lsattr lsmod lzmacat makedevs \ + md5sum mdev mesg microcom mkdir mkfifo mkfs.minix mknod mkswap \ + mktemp modprobe more mount mountpoint msh mt mv nameif nc \ + netstat nice nmeter nohup nslookup od openvt passwd patch \ + pgrep pidof ping ping6 pipe_progress pivot_root pkill poweroff \ + printenv printf ps pscan pwd raidautorun rdate readahead \ + readlink readprofile realpath reboot renice reset resize rm \ + rmdir rmmod route rpm rpm2cpio run-parts runlevel runsv \ + runsvdir rx script sed sendmail seq setarch setconsole \ + setkeycodes setlogcons setsid setuidgid sh sha1sum slattach \ + sleep softlimit sort split start-stop-daemon stat strings \ + stty su sulogin sum sv svlogd swapoff swapon switch_root \ + sync sysctl syslogd tac tail tar taskset tcpsvd tee telnet \ + telnetd test tftp tftpd time top touch tr traceroute \ + true tty ttysize udhcpc udhcpd udpsvd umount uname uncompress \ + unexpand uniq unix2dos unlzma unzip uptime usleep uudecode \ + uuencode vconfig vi vlock watch watchdog wc wget which \ + who whoami xargs yes zcat zcip" + + type busybox >/dev/null + + if [ $? -ne 0 ]; then + echo "busybox executable is not accessible" + return 1 + fi + + file $(which busybox) | grep -q "statically linked" + if [ $? -ne 0 ]; then + echo "warning : busybox is not statically linked." + echo "warning : The template script may not correctly" + echo "warning : setup the container environment." + fi + + # copy busybox in the rootfs + cp $(which busybox) $rootfs/bin + if [ $? -ne 0 ]; then + echo "failed to copy busybox in the rootfs" + return 1 + fi + + # do hardlink to busybox for the different commands + for i in $functions; do ln $rootfs/bin/busybox $rootfs/bin/$i; done + + # relink /sbin/init + ln $rootfs/bin/busybox $rootfs/sbin/init + + # passwd exec must be setuid + chmod +s $rootfs/bin/passwd + touch $rootfs/etc/shadow + chroot $rootfs /bin/passwd -d root + + echo "No password for 'root', please change !" + + return 0 +} + +copy_configuration() +{ + path=$1 + rootfs=$2 + name=$3 + +grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config +cat <> $path/config +lxc.utsname = $name +lxc.tty = 1 +lxc.pts = 1 +# uncomment the next line to run the container unconfined: +#lxc.aa_profile = unconfined +EOF + +if [ -d "$rootfs/lib" ]; then +cat <> $path/config +lxc.mount.entry=/lib $rootfs/lib none ro,bind 0 0 +lxc.mount.entry=/usr/lib $rootfs/usr/lib none ro,bind 0 0 +EOF +fi + +if [ -d "/lib64" ] && [ -d "$rootfs/lib64" ]; then +cat <> $path/config +lxc.mount.entry=/lib64 $rootfs/lib64 none ro,bind 0 0 +EOF +fi + +if [ -d "/usr/lib64" ] && [ -d "$rootfs/usr/lib64" ]; then +cat <> $path/config +lxc.mount.entry=/usr/lib64 $rootfs/usr/lib64 none ro,bind 0 0 +EOF +fi +} + +usage() +{ + cat < +EOF + return 0 +} + +options=$(getopt -o hp:n: -l help,path:,name: -- "$@") +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;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ "$(id -u)" != "0" ]; then + echo "This script should be run as 'root'" + exit 1 +fi + +if [ -z "$path" ]; then + echo "'path' parameter is required" + exit 1 +fi + +# detect rootfs +config="$path/config" +if grep -q '^lxc.rootfs' $config 2>/dev/null ; then + rootfs=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'` +else + rootfs=$path/rootfs +fi + +install_busybox $rootfs $name +if [ $? -ne 0 ]; then + echo "failed to install busybox's rootfs" + exit 1 +fi + +configure_busybox $rootfs +if [ $? -ne 0 ]; then + echo "failed to configure busybox template" + exit 1 +fi + +copy_configuration $path $rootfs $name +if [ $? -ne 0 ]; then + echo "failed to write configuration file" + exit 1 +fi diff --git a/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-debian b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-debian new file mode 100755 index 0000000..8d8a26c --- /dev/null +++ b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-debian @@ -0,0 +1,343 @@ +#!/bin/bash + +# +# lxc: linux Container library + +# Authors: +# Daniel Lezcano + +# 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 + +SUITE=${SUITE:-squeeze} +MIRROR=${MIRROR:-http://cdn.debian.net/debian} + +configure_debian() +{ + rootfs=$1 + hostname=$2 + + # squeeze only has /dev/tty and /dev/tty0 by default, + # therefore creating missing device nodes for tty1-4. + for tty in $(seq 1 4); do + if [ ! -e $rootfs/dev/tty$tty ]; then + mknod $rootfs/dev/tty$tty c 4 $tty + fi + done + + # configure the inittab + cat < $rootfs/etc/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 +p6::ctrlaltdel:/sbin/init 6 +p0::powerfail:/sbin/init 0 +EOF + + # disable selinux in debian + mkdir -p $rootfs/selinux + echo 0 > $rootfs/selinux/enforce + + # configure the network using the dhcp + cat < $rootfs/etc/network/interfaces +auto lo +iface lo inet loopback + +auto eth0 +iface eth0 inet dhcp +EOF + + # set the hostname + cat < $rootfs/etc/hostname +$hostname +EOF + + # reconfigure some services + if [ -z "$LANG" ]; then + chroot $rootfs locale-gen en_US.UTF-8 UTF-8 + chroot $rootfs update-locale LANG=en_US.UTF-8 + else + chroot $rootfs locale-gen $LANG $(echo $LANG | cut -d. -f2) + chroot $rootfs update-locale LANG=$LANG + fi + + # remove pointless services in a container + chroot $rootfs /usr/sbin/update-rc.d -f checkroot.sh remove + chroot $rootfs /usr/sbin/update-rc.d -f umountfs remove + chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh remove + chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh remove + + echo "root:root" | chroot $rootfs chpasswd + echo "Root password is 'root', please change !" + + return 0 +} + +cleanup() +{ + rm -rf $cache/partial-$SUITE-$arch + rm -rf $cache/rootfs-$SUITE-$arch +} + +download_debian() +{ + packages=\ +ifupdown,\ +locales,\ +libui-dialog-perl,\ +dialog,\ +isc-dhcp-client,\ +netbase,\ +net-tools,\ +iproute,\ +openssh-server + + cache=$1 + arch=$2 + + trap cleanup EXIT SIGHUP SIGINT SIGTERM + # check the mini debian was not already downloaded + mkdir -p "$cache/partial-$SUITE-$arch" + if [ $? -ne 0 ]; then + echo "Failed to create '$cache/partial-$SUITE-$arch' directory" + return 1 + fi + + # download a mini debian into a cache + echo "Downloading debian minimal ..." + debootstrap --verbose --variant=minbase --arch=$arch \ + --include=$packages \ + "$SUITE" "$cache/partial-$SUITE-$arch" $MIRROR + if [ $? -ne 0 ]; then + echo "Failed to download the rootfs, aborting." + return 1 + fi + + mv "$1/partial-$SUITE-$arch" "$1/rootfs-$SUITE-$arch" + echo "Download complete." + trap EXIT + trap SIGINT + trap SIGTERM + trap SIGHUP + + return 0 +} + +copy_debian() +{ + cache=$1 + arch=$2 + rootfs=$3 + + # make a local copy of the minidebian + echo -n "Copying rootfs to $rootfs..." + mkdir -p $rootfs + rsync -a "$cache/rootfs-$SUITE-$arch"/ $rootfs/ || return 1 + return 0 +} + +install_debian() +{ + cache="/var/cache/lxc/debian" + rootfs=$1 + mkdir -p /var/lock/subsys/ + ( + flock -x 200 + if [ $? -ne 0 ]; then + echo "Cache repository is busy." + return 1 + fi + + arch=$(dpkg --print-architecture) + + echo "Checking cache download in $cache/rootfs-$SUITE-$arch ... " + if [ ! -e "$cache/rootfs-$SUITE-$arch" ]; then + download_debian $cache $arch + if [ $? -ne 0 ]; then + echo "Failed to download 'debian base'" + return 1 + fi + fi + + copy_debian $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 + hostname=$3 + + grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config + cat <> $path/config +lxc.tty = 4 +lxc.pts = 1024 +lxc.utsname = $hostname +# 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 + +# mounts point +lxc.mount.entry=proc proc proc nodev,noexec,nosuid 0 0 +lxc.mount.entry=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/debian" + + if [ ! -e $cache ]; then + exit 0 + fi + + # lock, so we won't purge while someone is creating a repository + ( + flock -n -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 debootstrap +if [ $? -ne 0 ]; then + echo "'debootstrap' 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 + +# detect rootfs +config="$path/config" +if grep -q '^lxc.rootfs' $config 2>/dev/null ; then + rootfs=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'` +else + rootfs=$path/rootfs +fi + + +install_debian $rootfs +if [ $? -ne 0 ]; then + echo "failed to install debian" + exit 1 +fi + +configure_debian $rootfs $name +if [ $? -ne 0 ]; then + echo "failed to configure debian 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 diff --git a/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-fedora b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-fedora new file mode 100755 index 0000000..fbcd69e --- /dev/null +++ b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-fedora @@ -0,0 +1,421 @@ +#!/bin/bash + +# +# template script for generating fedora container for LXC +# + +# +# lxc: linux Container library + +# Authors: +# Daniel Lezcano +# Ramez Hanna + +# 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 + +#Configurations +arch=$(arch) +cache_base=/var/cache/lxc/fedora/$arch +default_path=/var/lib/lxc +root_password=root + +# is this fedora? +[ -f /etc/fedora-release ] && is_fedora=true + +if [ "$arch" = "i686" ]; then + arch=i386 +fi + +configure_fedora() +{ + + # disable selinux in fedora + mkdir -p $rootfs_path/selinux + echo 0 > $rootfs_path/selinux/enforce + + # configure the network using the dhcp + cat < ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0 +DEVICE=eth0 +BOOTPROTO=dhcp +ONBOOT=yes +HOSTNAME=${name} +NM_CONTROLLED=no +TYPE=Ethernet +MTU=${MTU} +EOF + + # set the hostname + cat < ${rootfs_path}/etc/sysconfig/network +NETWORKING=yes +HOSTNAME=${name} +EOF + + # set minimal hosts + cat < $rootfs_path/etc/hosts +127.0.0.1 localhost $name +EOF + + sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.sysinit + sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.d/rc.sysinit + # don't mount devpts, for pete's sake + sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.sysinit + sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.d/rc.sysinit + + chroot ${rootfs_path} chkconfig udev-post off + chroot ${rootfs_path} chkconfig network on + + dev_path="${rootfs_path}/dev" + rm -rf $dev_path + mkdir -p $dev_path + mknod -m 666 ${dev_path}/null c 1 3 + mknod -m 666 ${dev_path}/zero c 1 5 + mknod -m 666 ${dev_path}/random c 1 8 + mknod -m 666 ${dev_path}/urandom c 1 9 + mkdir -m 755 ${dev_path}/pts + mkdir -m 1777 ${dev_path}/shm + mknod -m 666 ${dev_path}/tty c 5 0 + mknod -m 666 ${dev_path}/tty0 c 4 0 + mknod -m 666 ${dev_path}/tty1 c 4 1 + mknod -m 666 ${dev_path}/tty2 c 4 2 + mknod -m 666 ${dev_path}/tty3 c 4 3 + mknod -m 666 ${dev_path}/tty4 c 4 4 + mknod -m 600 ${dev_path}/console c 5 1 + mknod -m 666 ${dev_path}/full c 1 7 + mknod -m 600 ${dev_path}/initctl p + mknod -m 666 ${dev_path}/ptmx c 5 2 + + echo "setting root passwd to $root_password" + echo "root:$root_password" | chroot $rootfs_path chpasswd + + # specifying this in the initial packages doesn't always work. + echo "installing fedora-release package" + chroot ${rootfs_path} yum --releasever=${release} -y install fedora-release + + # silence some needless startup errors + touch ${rootfs_path}/etc/fstab + + # give us a console on /dev/console + sed -i 's/ACTIVE_CONSOLES=.*$/ACTIVE_CONSOLES="\/dev\/console \/dev\/tty[1-4]"/' \ + ${rootfs_path}/etc/sysconfig/init + + return 0 +} + +download_fedora() +{ + + # check the mini fedora was not already downloaded + INSTALL_ROOT=$cache/partial + mkdir -p $INSTALL_ROOT + if [ $? -ne 0 ]; then + echo "Failed to create '$INSTALL_ROOT' directory" + return 1 + fi + + # download a mini fedora into a cache + echo "Downloading fedora minimal ..." + YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck" + PKG_LIST="yum initscripts passwd rsyslog vim-minimal dhclient chkconfig rootfiles policycoreutils fedora-release" + MIRRORLIST_URL="http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-$release&arch=$arch" + + DOWNLOAD_OK=no + for trynumber in 1 2 3; do + [ $trynumber != 1 ] && echo "Trying again..." + MIRROR_URL=$(curl -s -S -f "$MIRRORLIST_URL" | head -n2 | tail -n1) + if [ $? -ne 0 ] || [ -z "$MIRROR_URL" ]; then + echo "Failed to get a mirror" + continue + fi + RELEASE_URL="$MIRROR_URL/Packages/fedora-release-$release-1.noarch.rpm" + echo "Fetching from $RELEASE_URL" + curl -f "$RELEASE_URL" > $INSTALL_ROOT/fedora-release-$release.noarch.rpm + if [ $? -ne 0 ]; then + echo "Failed to download fedora release rpm" + continue + fi + DOWNLOAD_OK=yes + break + done + if [ $DOWNLOAD_OK != yes ]; then + echo "Aborting" + return 1 + fi + + mkdir -p $INSTALL_ROOT/var/lib/rpm + rpm --root $INSTALL_ROOT --initdb + rpm --root $INSTALL_ROOT -ivh $INSTALL_ROOT/fedora-release-$release.noarch.rpm + $YUM install $PKG_LIST + + if [ $? -ne 0 ]; then + echo "Failed to download the rootfs, aborting." + return 1 + fi + + mv "$INSTALL_ROOT" "$cache/rootfs" + echo "Download complete." + + return 0 +} + +copy_fedora() +{ + + # make a local copy of the minifedora + echo -n "Copying rootfs to $rootfs_path ..." + #cp -a $cache/rootfs-$arch $rootfs_path || return 1 + # i prefer rsync (no reason really) + mkdir -p $rootfs_path + rsync -a $cache/rootfs/ $rootfs_path/ + return 0 +} + +update_fedora() +{ + chroot $cache/rootfs yum -y update +} + +install_fedora() +{ + mkdir -p /var/lock/subsys/ + ( + flock -x 200 + if [ $? -ne 0 ]; then + echo "Cache repository is busy." + return 1 + fi + + echo "Checking cache download in $cache/rootfs ... " + if [ ! -e "$cache/rootfs" ]; then + download_fedora + if [ $? -ne 0 ]; then + echo "Failed to download 'fedora base'" + return 1 + fi + else + echo "Cache found. Updating..." + update_fedora + if [ $? -ne 0 ]; then + echo "Failed to update 'fedora base', continuing with last known good cache" + else + echo "Update finished" + fi + fi + + echo "Copy $cache/rootfs to $rootfs_path ... " + copy_fedora + if [ $? -ne 0 ]; then + echo "Failed to copy rootfs" + return 1 + fi + + return 0 + + ) 200>/var/lock/subsys/lxc + + return $? +} + +copy_configuration() +{ + + mkdir -p $config_path + grep -q "^lxc.rootfs" $config_path/config 2>/dev/null || echo "lxc.rootfs = $rootfs_path" >> $config_path/config + cat <> $config_path/config +lxc.utsname = $name +lxc.tty = 4 +lxc.pts = 1024 +lxc.mount = $config_path/fstab + +# uncomment the next line to run the container unconfined: +#lxc.aa_profile = unconfined + +#cgroups +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 < $config_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() +{ + + 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 for Fedora-$release..." + rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1 + exit 0 + + ) 200>/var/lock/subsys/lxc +} + +usage() +{ + cat < + [-p|--path=] [-c|--clean] [-R|--release=] [-A|--arch=] + [-h|--help] +Mandatory args: + -n,--name container name, used to as an identifier for that container from now on +Optional args: + -p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc. The container config will go under /var/lib/lxc in that case + -c,--clean clean the cache + -R,--release Fedora release for the new container. if the host is Fedora, then it will defaultto the host's release. + -A,--arch NOT USED YET. Define what arch the container will be [i686,x86_64] + -h,--help print this help +EOF + return 0 +} + +options=$(getopt -o hp:n:cR: -l help,path:,name:,clean,release: -- "$@") +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;; + -R|--release) release=$2; shift 2;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ ! -z "$clean" -a -z "$path" ]; then + clean || exit 1 + exit 0 +fi + +needed_pkgs="" +type yum >/dev/null 2>&1 +if [ $? -ne 0 ]; then + needed_pkgs="yum $needed_pkgs" +fi + +type curl >/dev/null 2>&1 +if [ $? -ne 0 ]; then + needed_pkgs="curl $needed_pkgs" +fi + +if [ -n "$needed_pkgs" ]; then + echo "Missing commands: $needed_pkgs" + echo "Please install these using \"sudo apt-get install $needed_pkgs\"" + exit 1 +fi + +if [ -z "$path" ]; then + path=$default_path +fi + +if [ -z "$release" ]; then + if [ "$is_fedora" ]; then + release=$(cat /etc/fedora-release |awk '/^Fedora/ {print $3}') + else + echo "This is not a fedora host and release missing, defaulting to 14. use -R|--release to specify release" + release=14 + fi +fi + +if [ "$(id -u)" != "0" ]; then + echo "This script should be run as 'root'" + exit 1 +fi + + +rootfs_path=$path/rootfs +# check for 'lxc.rootfs' passed in through default config by lxc-create +if grep -q '^lxc.rootfs' $path/config 2>/dev/null ; then + rootfs_path=`grep 'lxc.rootfs =' $path/config | awk -F= '{ print $2 }'` +fi +config_path=$default_path/$name +cache=$cache_base/$release + +revert() +{ + echo "Interrupted, so cleaning up" + lxc-destroy -n $name + # maybe was interrupted before copy config + rm -rf $path/$name + rm -rf $default_path/$name + echo "exiting..." + exit 1 +} + +trap revert SIGHUP SIGINT SIGTERM + +copy_configuration +if [ $? -ne 0 ]; then + echo "failed write configuration file" + exit 1 +fi + +install_fedora +if [ $? -ne 0 ]; then + echo "failed to install fedora" + exit 1 +fi + +configure_fedora +if [ $? -ne 0 ]; then + echo "failed to configure fedora for a container" + exit 1 +fi + + +if [ ! -z $clean ]; then + clean || exit 1 + exit 0 +fi +echo "container rootfs and config created" diff --git a/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-opensuse b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-opensuse new file mode 100755 index 0000000..26cee6a --- /dev/null +++ b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-opensuse @@ -0,0 +1,398 @@ +#!/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=12.1 + +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 + + # set /dev/console as securetty + cat << EOF >> $rootfs/etc/securetty +console +EOF + + cat <> $rootfs/etc/sysconfig/boot +# disable root fsck +ROOTFS_FSCK="0" +ROOTFS_BLKDEV="/dev/null" +EOF + + + # remove pointless services in a container + chroot $rootfs /sbin/insserv -r -f boot.udev boot.loadmodules boot.device-mapper boot.clock boot.swap boot.klog kbd + + echo "Please change root-password !" + echo "root:root" | chroot $rootfs chpasswd + + return 0 +} + +download_opensuse() +{ + cache=$1 + arch=$2 + + if [ ! -x /usr/bin/build ]; then + echo "Could not create openSUSE template :" + echo "you need to install \"build\" package" + return 1 + fi + + # 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-packages" + zypper --quiet --root $cache/partial-$arch-packages --non-interactive ar http://download.opensuse.org/distribution/$DISTRO/repo/oss/ repo-oss + zypper --quiet --root $cache/partial-$arch-packages --non-interactive ar http://download.opensuse.org/update/$DISTRO/ update + zypper --quiet --root $cache/partial-$arch-packages --non-interactive --gpg-auto-import-keys update + zypper --root $cache/partial-$arch-packages --non-interactive in --auto-agree-with-licenses --download-only zypper lxc patterns-openSUSE-base sysvinit-init + cat > $cache/partial-$arch-packages/opensuse.conf << EOF +Preinstall: aaa_base bash coreutils diffutils +Preinstall: filesystem fillup glibc grep insserv libacl1 libattr1 +Preinstall: libbz2-1 libgcc46 libxcrypt libncurses5 pam +Preinstall: permissions libreadline6 rpm sed tar zlib libselinux1 +Preinstall: liblzma5 libcap2 libpcre0 +Preinstall: libpopt0 libelf1 liblua5_1 + +RunScripts: aaa_base + +Support: zypper +Support: patterns-openSUSE-base +Support: lxc +Prefer: sysvinit-init + +Ignore: patterns-openSUSE-base:patterns-openSUSE-yast2_install_wf +EOF + + CLEAN_BUILD=1 BUILD_ROOT="$cache/partial-$arch" BUILD_DIST="$cache/partial-$arch-packages/opensuse.conf" /usr/lib/build/init_buildsystem --clean --cachedir $cache/partial-$arch-cache --repository $cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/suse/$arch --repository $cache/partial-$arch-packages/var/cache/zypp/packages/repo-oss/suse/noarch + chroot $cache/partial-$arch /usr/bin/zypper --quiet --non-interactive ar http://download.opensuse.org/distribution/$DISTRO/repo/oss repo-oss + chroot $cache/partial-$arch /usr/bin/zypper --quiet --non-interactive ar http://download.opensuse.org/update/$DISTRO/ update + chroot $cache/partial-$arch rpm -e patterns-openSUSE-base + umount $cache/partial-$arch/proc +# really clean the image + rm -fr $cache/partial-$arch/{.build,.guessed_dist,.srcfiles*,installed-pkg} + rm -fr $cache/partial-$arch/dev +# make sure we have a minimal /dev + 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 +# create mtab symlink + rm -f $cache/partial-$arch/etc/mtab + ln -sf /proc/self/mounts $cache/partial-$arch/etc/mtab + if [ $? -ne 0 ]; then + echo "Failed to download the rootfs, aborting." + return 1 + fi + + rm -fr "$cache/partial-$arch-packages" + 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 + + grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config + cat <> $path/config +lxc.utsname = $name + +lxc.tty = 4 +lxc.pts = 1024 +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 + +# detect rootfs +config="$path/config" +if grep -q '^lxc.rootfs' $config 2>/dev/null ; then + rootfs=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'` +else + rootfs=$path/rootfs +fi + +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 diff --git a/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-sshd b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-sshd new file mode 100755 index 0000000..80362a0 --- /dev/null +++ b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-sshd @@ -0,0 +1,233 @@ +#!/bin/bash + +# +# lxc: linux Container library + +# Authors: +# Daniel Lezcano + +# 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 + +install_sshd() +{ + rootfs=$1 + + tree="\ +$rootfs/var/run/sshd \ +$rootfs/var/empty/sshd \ +$rootfs/var/lib/empty/sshd \ +$rootfs/etc/ssh \ +$rootfs/dev/shm \ +$rootfs/run/shm \ +$rootfs/proc \ +$rootfs/bin \ +$rootfs/sbin \ +$rootfs/usr \ +$rootfs/tmp \ +$rootfs/home \ +$rootfs/root \ +$rootfs/lib \ +$rootfs/lib64" + + mkdir -p $tree + if [ $? -ne 0 ]; then + return 1 + fi + + return 0 +} + +configure_sshd() +{ + rootfs=$1 + + cat < $rootfs/etc/passwd +root:x:0:0:root:/root:/bin/bash +sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin +EOF + + cat < $rootfs/etc/group +root:x:0:root +sshd:x:74: +EOF + +ssh-keygen -t rsa -f $rootfs/etc/ssh/ssh_host_rsa_key +ssh-keygen -t dsa -f $rootfs/etc/ssh/ssh_host_dsa_key + + # by default setup root password with no password + cat < $rootfs/etc/ssh/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 + + if [ -n "$auth_key" -a -f "$auth_key" ]; then + u_path="/root/.ssh" + root_u_path="$rootfs/$u_path" + mkdir -p $root_u_path + cp $auth_key "$root_u_path/authorized_keys" + chown -R 0:0 "$rootfs/$u_path" + chmod 700 "$rootfs/$u_path" + + echo "Inserted SSH public key from $auth_key into /home/ubuntu/.ssh/authorized_keys" + fi + + return 0 +} + +copy_configuration() +{ + path=$1 + rootfs=$2 + name=$3 + + grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config + cat <> $path/config +lxc.utsname = $name +lxc.pts = 1024 +# uncomment the next line to run the container unconfined: +#lxc.aa_profile = unconfined +lxc.mount.entry=/dev dev none ro,bind 0 0 +lxc.mount.entry=/lib lib none ro,bind 0 0 +lxc.mount.entry=/bin bin none ro,bind 0 0 +lxc.mount.entry=/usr usr none ro,bind 0 0 +lxc.mount.entry=/sbin sbin none ro,bind 0 0 +lxc.mount.entry=tmpfs var/run/sshd tmpfs mode=0644 0 0 +lxc.mount.entry=/usr/share/lxc/templates/lxc-sshd sbin/init none bind 0 0 +lxc.mount.entry=proc proc proc nodev,noexec,nosuid 0 0 +EOF + + # if no .ipv4 section in config, then have the container run dhcp + grep -q "^lxc.network.ipv4" $path/config || touch $rootfs/run-dhcp + + if [ "$(uname -m)" = "x86_64" ]; then + cat <> $path/config +lxc.mount.entry=/lib64 lib64 none ro,bind 0 0 +EOF + fi +} + +usage() +{ + cat < +EOF + return 0 +} + +options=$(getopt -o hp:n:S: -l help,path:,name:,auth-key: -- "$@") +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;; + -S|--auth-key) auth_key=$2; shift 2;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ "$(id -u)" != "0" ]; then + echo "This script should be run as 'root'" + exit 1 +fi + +if [ $0 == "/sbin/init" ]; then + + type ${libexecdir}/lxc-init + if [ $? -ne 0 ]; then + echo "'lxc-init is not accessible on the system" + exit 1 + fi + + type sshd + if [ $? -ne 0 ]; then + echo "'sshd' is not accessible on the system " + exit 1 + fi + + # run dhcp? + if [ -f /run-dhcp ]; then + type dhclient + if [ $? -ne 0 ]; then + echo "can't find dhclient" + exit 1 + fi + touch /etc/fstab + rm -f /dhclient.conf + cat > /dhclient.conf << EOF +send host-name ""; +EOF + ifconfig eth0 up + dhclient eth0 -cf /dhclient.conf + fi + + exec ${libexecdir}/lxc-init -- /usr/sbin/sshd + exit 1 +fi + +if [ -z "$path" ]; then + echo "'path' parameter is required" + exit 1 +fi + +# detect rootfs +config="$path/config" +if grep -q '^lxc.rootfs' $config 2>/dev/null ; then + rootfs=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'` +else + rootfs=$path/rootfs +fi + +install_sshd $rootfs +if [ $? -ne 0 ]; then + echo "failed to install sshd's rootfs" + exit 1 +fi + +configure_sshd $rootfs +if [ $? -ne 0 ]; then + echo "failed to configure sshd template" + exit 1 +fi + +copy_configuration $path $rootfs $name +if [ $? -ne 0 ]; then + echo "failed to write configuration file" + exit 1 +fi diff --git a/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-ubuntu b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-ubuntu new file mode 100755 index 0000000..4d4bc30 --- /dev/null +++ b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-ubuntu @@ -0,0 +1,719 @@ +#!/bin/bash + +# +# template script for generating ubuntu container for LXC +# +# This script consolidates and extends the existing lxc ubuntu scripts +# + +# Copyright © 2011 Serge Hallyn +# Copyright © 2010 Wilhelm Meier +# Author: Wilhelm Meier +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. + +# This program 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 General Public License for more details. + +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +set -e + +if [ -r /etc/default/lxc ]; then + . /etc/default/lxc +fi + +configure_ubuntu() +{ + rootfs=$1 + hostname=$2 + release=$3 + + # configure the network using the dhcp + cat < $rootfs/etc/network/interfaces +# This file describes the network interfaces available on your system +# and how to activate them. For more information, see interfaces(5). + +# The loopback network interface +auto lo +iface lo inet loopback + +auto eth0 +iface eth0 inet dhcp +EOF + + # set the hostname + cat < $rootfs/etc/hostname +$hostname +EOF + # set minimal hosts + cat < $rootfs/etc/hosts +127.0.0.1 localhost +127.0.1.1 $hostname + +# The following lines are desirable for IPv6 capable hosts +::1 ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff00::0 ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +EOF + + if [ ! -f $rootfs/etc/init/container-detect.conf ]; then + # suppress log level output for udev + sed -i "s/=\"err\"/=0/" $rootfs/etc/udev/udev.conf + + # remove jobs for consoles 5 and 6 since we only create 4 consoles in + # this template + rm -f $rootfs/etc/init/tty{5,6}.conf + fi + + if [ -z "$bindhome" ]; then + chroot $rootfs useradd --create-home -s /bin/bash ubuntu + echo "ubuntu:ubuntu" | chroot $rootfs chpasswd + fi + + return 0 +} + +# finish setting up the user in the container by injecting ssh key and +# adding sudo group membership. +# passed-in user is either 'ubuntu' or the user to bind in from host. +finalize_user() +{ + user=$1 + + sudo_version=$(chroot $rootfs dpkg-query -W -f='${Version}' sudo) + + if chroot $rootfs dpkg --compare-versions $sudo_version gt "1.8.3p1-1"; then + groups="sudo" + else + groups="sudo admin" + fi + + for group in $groups; do + chroot $rootfs groupadd --system $group >/dev/null 2>&1 || true + chroot $rootfs adduser ${user} $group >/dev/null 2>&1 || true + done + + if [ -n "$auth_key" -a -f "$auth_key" ]; then + u_path="/home/${user}/.ssh" + root_u_path="$rootfs/$u_path" + + mkdir -p $root_u_path + cp $auth_key "$root_u_path/authorized_keys" + chroot $rootfs chown -R ${user}: "$u_path" + + echo "Inserted SSH public key from $auth_key into /home/${user}/.ssh/authorized_keys" + fi + return 0 +} + +write_sourceslist() +{ + # $1 => path to the rootfs + # $2 => architecture we want to add + # $3 => whether to use the multi-arch syntax or not + + case $2 in + amd64|i386) + MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu} + SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.ubuntu.com/ubuntu} + ;; + *) + MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports} + SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports} + ;; + esac + if [ -n "$3" ]; then + cat >> "$1/etc/apt/sources.list" << EOF +deb [arch=$2] $MIRROR ${release} main restricted universe multiverse +deb [arch=$2] $MIRROR ${release}-updates main restricted universe multiverse +deb [arch=$2] $SECURITY_MIRROR ${release}-security main restricted universe multiverse +EOF + else + cat >> "$1/etc/apt/sources.list" << EOF +deb $MIRROR ${release} main restricted universe multiverse +deb $MIRROR ${release}-updates main restricted universe multiverse +deb $SECURITY_MIRROR ${release}-security main restricted universe multiverse +EOF + fi +} + +cleanup() +{ + rm -rf $cache/partial-$arch + rm -rf $cache/rootfs-$arch +} + +suggest_flush() +{ + echo "Container upgrade failed. The container cache may be out of date," + echo "in which case flushing the case (see -F in the hep output) may help." +} + +download_ubuntu() +{ + cache=$1 + arch=$2 + release=$3 + + packages=vim,ssh + echo "installing packages: $packages" + + trap cleanup EXIT SIGHUP SIGINT SIGTERM + # check the mini ubuntu 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 ubuntu into a cache + echo "Downloading ubuntu $release minimal ..." + if [ -n "$(which qemu-debootstrap)" ]; then + qemu-debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR + else + debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR + fi + + if [ $? -ne 0 ]; then + echo "Failed to download the rootfs, aborting." + return 1 + fi + + # Serge isn't sure whether we should avoid doing this when + # $release == `distro-info -d` + echo "Installing updates" + > $cache/partial-$arch/etc/apt/sources.list + write_sourceslist $cache/partial-$arch/ $arch + + chroot "$1/partial-${arch}" apt-get update + if [ $? -ne 0 ]; then + echo "Failed to update the apt cache" + return 1 + fi + cat > "$1/partial-${arch}"/usr/sbin/policy-rc.d << EOF +#!/bin/sh +exit 101 +EOF + chmod +x "$1/partial-${arch}"/usr/sbin/policy-rc.d + + lxc-unshare -s MOUNT -- chroot "$1/partial-${arch}" apt-get dist-upgrade -y || { suggest_flush; false; } + rm -f "$1/partial-${arch}"/usr/sbin/policy-rc.d + + chroot "$1/partial-${arch}" apt-get clean + + mv "$1/partial-$arch" "$1/rootfs-$arch" + trap EXIT + trap SIGINT + trap SIGTERM + trap SIGHUP + echo "Download complete" + return 0 +} + +copy_ubuntu() +{ + cache=$1 + arch=$2 + rootfs=$3 + + # make a local copy of the miniubuntu + echo "Copying rootfs to $rootfs ..." + mkdir -p $rootfs + rsync -a $cache/rootfs-$arch/ $rootfs/ || return 1 + return 0 +} + +install_ubuntu() +{ + rootfs=$1 + release=$2 + flushcache=$3 + cache="/var/cache/lxc/$release" + mkdir -p /var/lock/subsys/ + + ( + flock -x 200 + if [ $? -ne 0 ]; then + echo "Cache repository is busy." + return 1 + fi + + + if [ $flushcache -eq 1 ]; then + echo "Flushing cache..." + rm -rf "$cache/partial-$arch" + rm -rf "$cache/rootfs-$arch" + fi + + echo "Checking cache download in $cache/rootfs-$arch ... " + if [ ! -e "$cache/rootfs-$arch" ]; then + download_ubuntu $cache $arch $release + if [ $? -ne 0 ]; then + echo "Failed to download 'ubuntu $release base'" + return 1 + fi + fi + + echo "Copy $cache/rootfs-$arch to $rootfs ... " + copy_ubuntu $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 + arch=$4 + release=$5 + + if [ $arch = "i386" ]; then + arch="i686" + fi + + ttydir="" + if [ -f $rootfs/etc/init/container-detect.conf ]; then + ttydir=" lxc" + fi + + # if there is exactly one veth network entry, make sure it has an + # associated hwaddr. + nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l` + if [ $nics -eq 1 ]; then + grep -q "^lxc.network.hwaddr" $path/config || cat <> $path/config +lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//') +EOF + fi + + grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config + cat <> $path/config +lxc.utsname = $name + +lxc.devttydir =$ttydir +lxc.tty = 4 +lxc.pts = 1024 +lxc.mount = $path/fstab +lxc.arch = $arch +lxc.cap.drop = sys_module mac_admin mac_override +lxc.pivotdir = lxc_putold + +# uncomment the next line to run the container unconfined: +#lxc.aa_profile = unconfined + +lxc.cgroup.devices.deny = a +# Allow any mknod (but not using the node) +lxc.cgroup.devices.allow = c *:* m +lxc.cgroup.devices.allow = b *:* m +# /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 +#fuse +lxc.cgroup.devices.allow = c 10:229 rwm +#tun +lxc.cgroup.devices.allow = c 10:200 rwm +#full +lxc.cgroup.devices.allow = c 1:7 rwm +#hpet +lxc.cgroup.devices.allow = c 10:228 rwm +#kvm +lxc.cgroup.devices.allow = c 10:232 rwm +EOF + + cat < $path/fstab +proc proc proc nodev,noexec,nosuid 0 0 +sysfs sys sysfs defaults 0 0 +devtmpfs dev devtmpfs defaults 0 0 +EOF + + if [ $? -ne 0 ]; then + echo "Failed to add configuration" + return 1 + fi + + return 0 +} + +trim() +{ + rootfs=$1 + release=$2 + + # provide the lxc service + cat < $rootfs/etc/init/lxc.conf +# fake some events needed for correct startup other services + +description "Container Upstart" + +start on startup + +script + rm -rf /var/run/*.pid + rm -rf /var/run/network/* + /sbin/initctl emit stopped JOB=udevtrigger --no-wait + /sbin/initctl emit started JOB=udev --no-wait +end script +EOF + + # fix buggus runlevel with sshd + cat < $rootfs/etc/init/ssh.conf +# ssh - OpenBSD Secure Shell server +# +# The OpenSSH server provides secure shell access to the system. + +description "OpenSSH server" + +start on filesystem +stop on runlevel [!2345] + +expect fork +respawn +respawn limit 10 5 +umask 022 +# replaces SSHD_OOM_ADJUST in /etc/default/ssh +oom never + +pre-start script + test -x /usr/sbin/sshd || { stop; exit 0; } + test -e /etc/ssh/sshd_not_to_be_run && { stop; exit 0; } + test -c /dev/null || { stop; exit 0; } + + mkdir -p -m0755 /var/run/sshd +end script + +# if you used to set SSHD_OPTS in /etc/default/ssh, you can change the +# 'exec' line here instead +exec /usr/sbin/sshd +EOF + + cat < $rootfs/etc/init/console.conf +# console - getty +# +# This service maintains a console on tty1 from the point the system is +# started until it is shut down again. + +start on stopped rc RUNLEVEL=[2345] +stop on runlevel [!2345] + +respawn +exec /sbin/getty -8 38400 /dev/console +EOF + + cat < $rootfs/lib/init/fstab +# /lib/init/fstab: cleared out for bare-bones lxc +EOF + + # reconfigure some services + if [ -z "$LANG" ]; then + chroot $rootfs locale-gen en_US.UTF-8 + chroot $rootfs update-locale LANG=en_US.UTF-8 + else + chroot $rootfs locale-gen $LANG + chroot $rootfs update-locale LANG=$LANG + fi + + # remove pointless services in a container + chroot $rootfs /usr/sbin/update-rc.d -f ondemand remove + + chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls u*.conf); do mv $f $f.orig; done' + chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls tty[2-9].conf); do mv $f $f.orig; done' + chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls plymouth*.conf); do mv $f $f.orig; done' + chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls hwclock*.conf); do mv $f $f.orig; done' + chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls module*.conf); do mv $f $f.orig; done' + + # if this isn't lucid, then we need to twiddle the network upstart bits :( + if [ $release != "lucid" ]; then + sed -i 's/^.*emission handled.*$/echo Emitting lo/' $rootfs/etc/network/if-up.d/upstart + fi +} + +post_process() +{ + rootfs=$1 + release=$2 + trim_container=$3 + + if [ $trim_container -eq 1 ]; then + trim $rootfs $release + elif [ ! -f $rootfs/etc/init/container-detect.conf ]; then + # Make sure we have a working resolv.conf + cresolvonf="${rootfs}/etc/resolv.conf" + mv $cresolvonf ${cresolvonf}.lxcbak + cat /etc/resolv.conf > ${cresolvonf} + + # for lucid, if not trimming, then add the ubuntu-virt + # ppa and install lxcguest + if [ $release = "lucid" ]; then + chroot $rootfs apt-get update + chroot $rootfs apt-get install --force-yes -y python-software-properties + chroot $rootfs add-apt-repository ppa:ubuntu-virt/ppa + fi + + chroot $rootfs apt-get update + chroot $rootfs apt-get install --force-yes -y lxcguest + + # Restore old resolv.conf + rm -f ${cresolvonf} + mv ${cresolvonf}.lxcbak ${cresolvonf} + fi + + # If the container isn't running a native architecture, setup multiarch + if [ -x "$(ls -1 ${rootfs}/usr/bin/qemu-*-static 2>/dev/null)" ]; then + dpkg_version=$(chroot $rootfs dpkg-query -W -f='${Version}' dpkg) + if chroot $rootfs dpkg --compare-versions $dpkg_version ge "1.16.2"; then + chroot $rootfs dpkg --add-architecture ${hostarch} + else + mkdir -p ${rootfs}/etc/dpkg/dpkg.cfg.d + echo "foreign-architecture ${hostarch}" > ${rootfs}/etc/dpkg/dpkg.cfg.d/lxc-multiarch + fi + + # Save existing value of MIRROR and SECURITY_MIRROR + DEFAULT_MIRROR=$MIRROR + DEFAULT_SECURITY_MIRROR=$SECURITY_MIRROR + + # Write a new sources.list containing both native and multiarch entries + > ${rootfs}/etc/apt/sources.list + write_sourceslist $rootfs $arch "native" + + MIRROR=$DEFAULT_MIRROR + SECURITY_MIRROR=$DEFAULT_SECURITY_MIRROR + write_sourceslist $rootfs $hostarch "multiarch" + + # Finally update the lists and install upstart using the host architecture + chroot $rootfs apt-get update + chroot $rootfs apt-get install --force-yes -y --no-install-recommends upstart:${hostarch} mountall:${hostarch} iproute:${hostarch} isc-dhcp-client:${hostarch} + fi + + # rmdir /dev/shm for containers that have /run/shm + # I'm afraid of doing rm -rf $rootfs/dev/shm, in case it did + # get bind mounted to the host's /run/shm. So try to rmdir + # it, and in case that fails move it out of the way. + if [ ! -L $rootfs/dev/shm ] && [ -d $rootfs/run/shm ] && [ -e $rootfs/dev/shm ]; then + mv $rootfs/dev/shm $rootfs/dev/shm.bak + ln -s /run/shm $rootfs/dev/shm + fi +} + +do_bindhome() +{ + rootfs=$1 + user=$2 + + # copy /etc/passwd, /etc/shadow, and /etc/group entries into container + pwd=`getent passwd $user` || { echo "Failed to copy password entry for $user"; false; } + echo $pwd >> $rootfs/etc/passwd + + # make sure user's shell exists in the container + shell=`echo $pwd | cut -d: -f 7` + if [ ! -x $rootfs/$shell ]; then + echo "shell $shell for user $user was not found in the container." + pkg=`dpkg -S $(readlink -m $shell) | cut -d ':' -f1` + echo "Installing $pkg" + chroot $rootfs apt-get --force-yes -y install $pkg + fi + + shad=`getent shadow $user` + echo "$shad" >> $rootfs/etc/shadow + + # bind-mount the user's path into the container's /home + h=`getent passwd $user | cut -d: -f 6` + mkdir -p $rootfs/$h + + # use relative path in container + h2=${h#/} + while [ ${h2:0:1} = "/" ]; do + h2=${h2#/} + done + echo "$h $h2 none bind 0 0" >> $path/fstab + + # Make sure the group exists in container + grp=`echo $pwd | cut -d: -f 4` # group number for $user + grpe=`getent group $grp` || return 0 # if host doesn't define grp, ignore in container + chroot $rootfs getent group "$grpe" || echo "$grpe" >> $rootfs/etc/group +} + +usage() +{ + cat <] [--trim] [-d|--debug] + [-F | --flush-cache] [-r|--release ] [ -S | --auth-key ] +release: the ubuntu release (e.g. precise): defaults to host release on ubuntu, otherwise uses latest LTS +trim: make a minimal (faster, but not upgrade-safe) container +bindhome: bind 's home into the container + The ubuntu user will not be created, and will have + sudo access. +arch: the container architecture (e.g. amd64): defaults to host arch +auth-key: SSH Public key file to inject into container +EOF + return 0 +} + +options=$(getopt -o a:b:hp:r:xn:FS:d -l arch:,bindhome:,help,path:,release:,trim,name:,flush-cache,auth-key:,debug -- "$@") +if [ $? -ne 0 ]; then + usage $(basename $0) + exit 1 +fi +eval set -- "$options" + +release=precise # Default to the last Ubuntu LTS release for non-Ubuntu systems +if [ -f /etc/lsb-release ]; then + . /etc/lsb-release + if [ "$DISTRIB_ID" = "Ubuntu" ]; then + release=$DISTRIB_CODENAME + fi +fi + +bindhome= +arch=$(arch) + +# Code taken from debootstrap +if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then + arch=`/usr/bin/dpkg --print-architecture` +elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then + arch=`/usr/bin/udpkg --print-architecture` +else + arch=$(arch) + if [ "$arch" = "i686" ]; then + arch="i386" + elif [ "$arch" = "x86_64" ]; then + arch="amd64" + elif [ "$arch" = "armv7l" ]; then + arch="armel" + fi +fi + +debug=0 +trim_container=0 +hostarch=$arch +flushcache=0 +while true +do + case "$1" in + -h|--help) usage $0 && exit 0;; + -p|--path) path=$2; shift 2;; + -n|--name) name=$2; shift 2;; + -F|--flush-cache) flushcache=1; shift 1;; + -r|--release) release=$2; shift 2;; + -b|--bindhome) bindhome=$2; shift 2;; + -a|--arch) arch=$2; shift 2;; + -x|--trim) trim_container=1; shift 1;; + -S|--auth-key) auth_key=$2; shift 2;; + -d|--debug) debug=1; shift 1;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ $debug -eq 1 ]; then + set -x +fi + +if [ -n "$bindhome" ]; then + pwd=`getent passwd $bindhome` + if [ $? -ne 0 ]; then + echo "Error: no password entry found for $bindhome" + exit 1 + fi +fi + + +if [ "$arch" == "i686" ]; then + arch=i386 +fi + +if [ $hostarch = "i386" -a $arch = "amd64" ]; then + echo "can't create amd64 container on i386" + exit 1 +fi + +type debootstrap +if [ $? -ne 0 ]; then + echo "'debootstrap' 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 + +# detect rootfs +config="$path/config" +if grep -q '^lxc.rootfs' $config 2>/dev/null ; then + rootfs=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'` +else + rootfs=$path/rootfs +fi + +install_ubuntu $rootfs $release $flushcache +if [ $? -ne 0 ]; then + echo "failed to install ubuntu $release" + exit 1 +fi + +configure_ubuntu $rootfs $name $release +if [ $? -ne 0 ]; then + echo "failed to configure ubuntu $release for a container" + exit 1 +fi + +copy_configuration $path $rootfs $name $arch $release +if [ $? -ne 0 ]; then + echo "failed write configuration file" + exit 1 +fi + +post_process $rootfs $release $trim_container + +if [ -n "$bindhome" ]; then + do_bindhome $rootfs $bindhome + finalize_user $bindhome +else + finalize_user ubuntu +fi + +echo "" +echo "##" +if [ -n "$bindhome" ]; then + echo "# Log in as user $bindhome" +else + echo "# The default user is 'ubuntu' with password 'ubuntu'!" + echo "# Use the 'sudo' command to run tasks as root in the container." +fi +echo "##" +echo "" diff --git a/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-ubuntu-cloud b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-ubuntu-cloud new file mode 100755 index 0000000..16de831 --- /dev/null +++ b/lxc/0.8.0~rc1-4ubuntu37/templates/lxc-ubuntu-cloud @@ -0,0 +1,407 @@ +#!/bin/bash + +# template script for generating ubuntu container for LXC based on released cloud +# images +# +# Copyright © 2012 Serge Hallyn +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. + +# This program 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 General Public License for more details. + +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +set -e + +if [ -r /etc/default/lxc ]; then + . /etc/default/lxc +fi + +copy_configuration() +{ + path=$1 + rootfs=$2 + name=$3 + arch=$4 + release=$5 + + if [ $arch = "i386" ]; then + arch="i686" + fi + + # if there is exactly one veth network entry, make sure it has an + # associated hwaddr. + nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l` + if [ $nics -eq 1 ]; then + grep -q "^lxc.network.hwaddr" $path/config || cat <> $path/config +lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//') +EOF + fi + + grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config + cat <> $path/config +lxc.utsname = $name + +lxc.tty = 4 +lxc.pts = 1024 +lxc.mount = $path/fstab +lxc.arch = $arch +lxc.cap.drop = sys_module mac_admin +lxc.pivotdir = lxc_putold + +# uncomment the next line to run the container unconfined: +#lxc.aa_profile = unconfined + +lxc.cgroup.devices.deny = a +# Allow any mknod (but not using the node) +lxc.cgroup.devices.allow = c *:* m +lxc.cgroup.devices.allow = b *:* m +# /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 +#fuse +lxc.cgroup.devices.allow = c 10:229 rwm +#tun +lxc.cgroup.devices.allow = c 10:200 rwm +#full +lxc.cgroup.devices.allow = c 1:7 rwm +#hpet +lxc.cgroup.devices.allow = c 10:228 rwm +#kvm +lxc.cgroup.devices.allow = c 10:232 rwm +EOF + + cat < $path/fstab +proc proc proc nodev,noexec,nosuid 0 0 +sysfs sys sysfs defaults 0 0 +devtmpfs dev devtmpfs defaults 0 0 +EOF + + # rmdir /dev/shm for containers that have /run/shm + # I'm afraid of doing rm -rf $rootfs/dev/shm, in case it did + # get bind mounted to the host's /run/shm. So try to rmdir + # it, and in case that fails move it out of the way. + if [ ! -L $rootfs/dev/shm ] && [ -d $rootfs/run/shm ] && [ -e $rootfs/dev/shm ]; then + mv $rootfs/dev/shm $rootfs/dev/shm.bak + ln -s /run/shm $rootfs/dev/shm + fi + + return 0 +} + +usage() +{ + cat < ]: Release name of container, defaults to host +[ -a | --arch ]: Arhcitecture of container, defaults to host arcitecture +[ -C | --cloud ]: Configure container for use with meta-data service, defaults to no +[ -T | --tarball ]: Location of tarball +[ -d | --debug ]: Run with 'set -x' to debug errors +[ -s | --stream]: Use specified stream rather than 'released' + +Options, mutually exclusive of "-C" and "--cloud": + [ -i | --hostid ]: HostID for cloud-init, defaults to random string + [ -u | --userdata ]: Cloud-init user-data file to configure container on start + [ -S | --auth-key ]: SSH Public key file to inject into container + [ -L | --nolocales ]: Do not copy host's locales into container + +EOF + return 0 +} + +options=$(getopt -o a:hp:r:n:Fi:CLS:T:ds: -l arch:,help,path:,release:,name:,flush-cache,hostid:,auth-key:,cloud,no_locales,tarball:,debug,stream:,userdata: -- "$@") +if [ $? -ne 0 ]; then + usage $(basename $0) + exit 1 +fi +eval set -- "$options" + +release=lucid +if [ -f /etc/lsb-release ]; then + . /etc/lsb-release + case "$DISTRIB_CODENAME" in + lucid|natty|oneiric|precise|quantal) + release=$DISTRIB_CODENAME + ;; + esac +fi + +arch=$(arch) + +# Code taken from debootstrap +if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then + arch=`/usr/bin/dpkg --print-architecture` +elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then + arch=`/usr/bin/udpkg --print-architecture` +else + arch=$(arch) + if [ "$arch" = "i686" ]; then + arch="i386" + elif [ "$arch" = "x86_64" ]; then + arch="amd64" + elif [ "$arch" = "armv7l" ]; then + # note: arm images don't exist before oneiric; are called armhf in + # precise and later; and are not supported by the query, so we don't actually + # support them yet (see check later on). When Query2 is available, + # we'll use that to enable arm images. + arch="armel" + fi +fi + +debug=0 +hostarch=$arch +cloud=0 +locales=1 +flushcache=0 +stream="released" +while true +do + case "$1" in + -h|--help) usage $0 && exit 0;; + -p|--path) path=$2; shift 2;; + -n|--name) name=$2; shift 2;; + -F|--flush-cache) flushcache=1; shift 1;; + -r|--release) release=$2; shift 2;; + -a|--arch) arch=$2; shift 2;; + -i|--hostid) host_id=$2; shift 2;; + -u|--userdata) userdata=$2; shift 2;; + -C|--cloud) cloud=1; shift 1;; + -S|--auth-key) auth_key=$2; shift 2;; + -L|--no_locales) locales=0; shift 2;; + -T|--tarball) tarball=$2; shift 2;; + -d|--debug) debug=1; shift 1;; + -s|--stream) stream=$2; shift 2;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ $debug -eq 1 ]; then + set -x +fi + +if [ "$arch" == "i686" ]; then + arch=i386 +fi + +if [ $hostarch = "i386" -a $arch = "amd64" ]; then + echo "can't create amd64 container on i386" + exit 1 +fi + +if [ $arch != "i386" -a $arch != "amd64" ]; then + echo "Only i386 and amd64 are supported by the ubuntu cloud template." + exit 1 +fi + +if [ "$stream" != "daily" -a "$stream" != "released" ]; then + echo "Only 'daily' and 'released' streams are supported" + exit 1 +fi + +if [ -n "$userdata" ]; then + if [ ! -f "$userdata" ]; then + echo "Userdata ($userdata) does not exist" + exit 1 + else + userdata=`readlink -f $userdata` + fi +fi + +if [ -n "$auth_key" ]; then + if [ ! -f "$auth_key" ]; then + echo "--auth-key=${auth_key} must reference a file" + exit 1 + fi + auth_key=$(readlink -f "${auth_key}") || + { echo "failed to get full path for auth_key"; 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 + +# detect rootfs +config="$path/config" +if grep -q '^lxc.rootfs' $config 2>/dev/null ; then + rootfs=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'` +else + rootfs=$path/rootfs +fi + +type ubuntu-cloudimg-query +type wget + +# determine the url, tarball, and directory names +# download if needed +cache="/var/cache/lxc/cloud-$release" + +mkdir -p $cache + +if [ -n "$tarball" ]; then + url2="$tarball" +else + url1=`ubuntu-cloudimg-query $release $stream $arch --format "%{url}\n"` + url2=`echo $url1 | sed -e 's/.tar.gz/-root\0/'` +fi + +filename=`basename $url2` + +wgetcleanup() +{ + rm -f $filename +} + +buildcleanup() +{ + cd $rootfs + umount -l $cache/$xdir || true + rm -rf $cache +} + +# if the release doesn't have a *-rootfs.tar.gz, then create one from the +# cloudimg.tar.gz by extracting the .img, mounting it loopback, and creating +# a tarball from the mounted image. +build_root_tgz() +{ + url=$1 + filename=$2 + + xdir=`mktemp -d -p .` + tarname=`basename $url` + imgname="$release-*-cloudimg-$arch.img" + trap buildcleanup EXIT SIGHUP SIGINT SIGTERM + if [ $flushcache -eq 1 -o ! -f $cache/$tarname ]; then + rm -f $tarname + echo "Downloading cloud image from $url" + wget $url || { echo "Couldn't find cloud image $url."; exit 1; } + fi + echo "Creating new cached cloud image rootfs" + tar --wildcards -zxf $tarname $imgname + mount -o loop $imgname $xdir + (cd $xdir; tar zcf ../$filename .) + umount $xdir + rm -f $tarname $imgname + rmdir $xdir + echo "New cloud image cache created" + trap EXIT + trap SIGHUP + trap SIGINT + trap SIGTERM +} + +mkdir -p /var/lock/subsys/ +( + flock -x 200 + + cd $cache + if [ $flushcache -eq 1 ]; then + echo "Clearing the cached images" + rm -f $filename + fi + + trap wgetcleanup EXIT SIGHUP SIGINT SIGTERM + if [ ! -f $filename ]; then + wget $url2 || build_root_tgz $url1 $filename + fi + trap EXIT + trap SIGHUP + trap SIGINT + trap SIGTERM + + echo "Extracting container rootfs" + mkdir -p $rootfs + cd $rootfs + tar -zxf $cache/$filename + + + if [ $cloud -eq 0 ]; then + echo "Configuring for running outside of a cloud environment" + echo "If you want to configure for a cloud evironment, please use '-- -C' to create the container" + + seed_d=$rootfs/var/lib/cloud/seed/nocloud-net + rhostid=$(uuidgen | cut -c -8) + host_id=${hostid:-$rhostid} + mkdir -p $seed_d + + cat > "$seed_d/meta-data" <> "$seed_d/meta-data" + [ $? -eq 0 ] || + { echo "failed to write public keys to metadata"; exit 1; } + fi + + rm $rootfs/etc/hostname + + if [ $locales -eq 1 ]; then + cp /usr/lib/locale/locale-archive $rootfs/usr/lib/locale/locale-archive + fi + + if [ -f "$userdata" ]; then + echo "Using custom user-data" + cp $userdata $seed_d/user-data + else + + if [ -z "$MIRROR" ]; then + MIRROR="http://archive.ubuntu.com/ubuntu" + fi + + cat > "$seed_d/user-data" </var/lock/subsys/lxc-ubucloud + +copy_configuration $path $rootfs $name $arch $release + +echo "Container $name created." +exit 0 + +# vi: ts=4 expandtab