1. #!/bin/bash
  2.  
  3. #
  4. # template script for generating ubuntu container for LXC
  5. #
  6. # This script consolidates and extends the existing lxc ubuntu scripts
  7. #
  8.  
  9. # Copyright © 2011 Serge Hallyn <serge.hallyn@canonical.com>
  10. # Copyright © 2010 Wilhelm Meier
  11. # Author: Wilhelm Meier <wilhelm.meier@fh-kl.de>
  12. #
  13. # This program is free software; you can redistribute it and/or modify
  14. # it under the terms of the GNU General Public License version 2, as
  15. # published by the Free Software Foundation.
  16.  
  17. # This program is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. # GNU General Public License for more details.
  21.  
  22. # You should have received a copy of the GNU General Public License along
  23. # with this program; if not, write to the Free Software Foundation, Inc.,
  24. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  25. #
  26.  
  27. set -e
  28.  
  29. if [ -r /etc/default/lxc ]; then
  30.     . /etc/default/lxc
  31. fi
  32.  
  33. configure_ubuntu()
  34. {
  35.     rootfs=$1
  36.     hostname=$2
  37.     release=$3
  38.  
  39.    # configure the network using the dhcp
  40.     cat <<EOF > $rootfs/etc/network/interfaces
  41. # This file describes the network interfaces available on your system
  42. # and how to activate them. For more information, see interfaces(5).
  43.  
  44. # The loopback network interface
  45. auto lo
  46. iface lo inet loopback
  47.  
  48. auto eth0
  49. iface eth0 inet dhcp
  50. EOF
  51.  
  52.     # set the hostname
  53.     cat <<EOF > $rootfs/etc/hostname
  54. $hostname
  55. EOF
  56.     # set minimal hosts
  57.     cat <<EOF > $rootfs/etc/hosts
  58. 127.0.0.1   localhost
  59. 127.0.1.1   $hostname
  60.  
  61. # The following lines are desirable for IPv6 capable hosts
  62. ::1     ip6-localhost ip6-loopback
  63. fe00::0 ip6-localnet
  64. ff00::0 ip6-mcastprefix
  65. ff02::1 ip6-allnodes
  66. ff02::2 ip6-allrouters
  67. EOF
  68.  
  69.     if [ ! -f $rootfs/etc/init/container-detect.conf ]; then
  70.         # suppress log level output for udev
  71.         sed -i "s/=\"err\"/=0/" $rootfs/etc/udev/udev.conf
  72.  
  73.         # remove jobs for consoles 5 and 6 since we only create 4 consoles in
  74.         # this template
  75.         rm -f $rootfs/etc/init/tty{5,6}.conf
  76.     fi
  77.  
  78.     if [ -z "$bindhome" ]; then
  79.         chroot $rootfs useradd --create-home -s /bin/bash ubuntu
  80.         echo "ubuntu:ubuntu" | chroot $rootfs chpasswd
  81.     fi
  82.  
  83.     return 0
  84. }
  85.  
  86. # finish setting up the user in the container by injecting ssh key and
  87. # adding sudo group membership.
  88. # passed-in user is either 'ubuntu' or the user to bind in from host.
  89. finalize_user()
  90. {
  91.     user=$1
  92.  
  93.     sudo_version=$(chroot $rootfs dpkg-query -W -f='${Version}' sudo)
  94.  
  95.     if chroot $rootfs dpkg --compare-versions $sudo_version gt "1.8.3p1-1"; then
  96.         groups="sudo"
  97.     else
  98.         groups="sudo admin"
  99.     fi
  100.  
  101.     for group in $groups; do
  102.         chroot $rootfs groupadd --system $group >/dev/null 2>&1 || true
  103.         chroot $rootfs adduser ${user} $group >/dev/null 2>&1 || true
  104.     done
  105.  
  106.     if [ -n "$auth_key" -a -f "$auth_key" ]; then
  107.         u_path="/home/${user}/.ssh"
  108.         root_u_path="$rootfs/$u_path"
  109.  
  110.         mkdir -p $root_u_path
  111.         cp $auth_key "$root_u_path/authorized_keys"
  112.         chroot $rootfs chown -R ${user}: "$u_path"
  113.  
  114.         echo "Inserted SSH public key from $auth_key into /home/${user}/.ssh/authorized_keys"
  115.     fi
  116.     return 0
  117. }
  118.  
  119. write_sourceslist()
  120. {
  121.     # $1 => path to the rootfs
  122.     # $2 => architecture we want to add
  123.     # $3 => whether to use the multi-arch syntax or not
  124.  
  125.     case $2 in
  126.       amd64|i386)
  127.             MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu}
  128.             SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.ubuntu.com/ubuntu}
  129.             ;;
  130.       *)
  131.             MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
  132.             SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
  133.             ;;
  134.     esac
  135.     if [ -n "$3" ]; then
  136.         cat >> "$1/etc/apt/sources.list" << EOF
  137. deb [arch=$2] $MIRROR ${release} main restricted universe multiverse
  138. deb [arch=$2] $MIRROR ${release}-updates main restricted universe multiverse
  139. deb [arch=$2] $SECURITY_MIRROR ${release}-security main restricted universe multiverse
  140. EOF
  141.     else
  142.         cat >> "$1/etc/apt/sources.list" << EOF
  143. deb $MIRROR ${release} main restricted universe multiverse
  144. deb $MIRROR ${release}-updates main restricted universe multiverse
  145. deb $SECURITY_MIRROR ${release}-security main restricted universe multiverse
  146. EOF
  147.     fi
  148. }
  149.  
  150. download_ubuntu()
  151. {
  152.     cache=$1
  153.     arch=$2
  154.     release=$3
  155.  
  156.     packages=vim,ssh
  157.     echo "installing packages: $packages"
  158.  
  159.     # check the mini ubuntu was not already downloaded
  160.     mkdir -p "$cache/partial-$arch"
  161.     if [ $? -ne 0 ]; then
  162.         echo "Failed to create '$cache/partial-$arch' directory"
  163.         return 1
  164.     fi
  165.  
  166.     # download a mini ubuntu into a cache
  167.     echo "Downloading ubuntu $release minimal ..."
  168.     if [ -n "$(which qemu-debootstrap)" ]; then
  169.         qemu-debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
  170.     else
  171.         debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
  172.     fi
  173.  
  174.     if [ $? -ne 0 ]; then
  175.         echo "Failed to download the rootfs, aborting."
  176.             return 1
  177.     fi
  178.  
  179.     # Serge isn't sure whether we should avoid doing this when
  180.     # $release == `distro-info -d`
  181.     echo "Installing updates"
  182.     > $cache/partial-$arch/etc/apt/sources.list
  183.     write_sourceslist $cache/partial-$arch/ $arch
  184.  
  185.     chroot "$1/partial-${arch}" apt-get update
  186.     if [ $? -ne 0 ]; then
  187.         echo "Failed to update the apt cache"
  188.         return 1
  189.     fi
  190.     cat > "$1/partial-${arch}"/usr/sbin/policy-rc.d << EOF
  191. #!/bin/sh
  192. exit 101
  193. EOF
  194.     chmod +x "$1/partial-${arch}"/usr/sbin/policy-rc.d
  195.  
  196.     lxc-unshare -s MOUNT -- chroot "$1/partial-${arch}" apt-get dist-upgrade -y
  197.     ret=$?
  198.     rm -f "$1/partial-${arch}"/usr/sbin/policy-rc.d
  199.  
  200.     if [ $ret -ne 0 ]; then
  201.         echo "Failed to upgrade the cache"
  202.         return 1
  203.     fi
  204.  
  205.     mv "$1/partial-$arch" "$1/rootfs-$arch"
  206.     echo "Download complete"
  207.     return 0
  208. }
  209.  
  210. copy_ubuntu()
  211. {
  212.     cache=$1
  213.     arch=$2
  214.     rootfs=$3
  215.  
  216.     # make a local copy of the miniubuntu
  217.     echo "Copying rootfs to $rootfs ..."
  218.     mkdir -p $rootfs
  219.     rsync -a $cache/rootfs-$arch/ $rootfs/ || return 1
  220.     return 0
  221. }
  222.  
  223. install_ubuntu()
  224. {
  225.     rootfs=$1
  226.     release=$2
  227.     flushcache=$3
  228.     cache="/var/cache/lxc/$release"
  229.     mkdir -p /var/lock/subsys/
  230.  
  231.     (
  232.         flock -x 200
  233.         if [ $? -ne 0 ]; then
  234.             echo "Cache repository is busy."
  235.             return 1
  236.         fi
  237.  
  238.  
  239.         if [ $flushcache -eq 1 ]; then
  240.             echo "Flushing cache..."
  241.             rm -rf "$cache/partial-$arch"
  242.             rm -rf "$cache/rootfs-$arch"
  243.         fi
  244.  
  245.         echo "Checking cache download in $cache/rootfs-$arch ... "
  246.         if [ ! -e "$cache/rootfs-$arch" ]; then
  247.             download_ubuntu $cache $arch $release
  248.             if [ $? -ne 0 ]; then
  249.                 echo "Failed to download 'ubuntu $release base'"
  250.                 return 1
  251.             fi
  252.         fi
  253.  
  254.         echo "Copy $cache/rootfs-$arch to $rootfs ... "
  255.         copy_ubuntu $cache $arch $rootfs
  256.         if [ $? -ne 0 ]; then
  257.             echo "Failed to copy rootfs"
  258.             return 1
  259.         fi
  260.  
  261.         return 0
  262.  
  263.     ) 200>/var/lock/subsys/lxc
  264.  
  265.     return $?
  266. }
  267.  
  268. copy_configuration()
  269. {
  270.     path=$1
  271.     rootfs=$2
  272.     name=$3
  273.     arch=$4
  274.     release=$5
  275.  
  276.     if [ $arch = "i386" ]; then
  277.         arch="i686"
  278.     fi
  279.  
  280.     ttydir=""
  281.     if [ -f $rootfs/etc/init/container-detect.conf ]; then
  282.         ttydir=" lxc"
  283.     fi
  284.  
  285.     # if there is exactly one veth network entry, make sure it has an
  286.     # associated hwaddr.
  287.     nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l`
  288.     if [ $nics -eq 1 ]; then
  289.         grep -q "^lxc.network.hwaddr" $path/config || cat <<EOF >> $path/config
  290. lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')
  291. EOF
  292.     fi
  293.  
  294.     cat <<EOF >> $path/config
  295. lxc.utsname = $name
  296.  
  297. lxc.devttydir =$ttydir
  298. lxc.tty = 4
  299. lxc.pts = 1024
  300. lxc.rootfs = $rootfs
  301. lxc.mount  = $path/fstab
  302. lxc.arch = $arch
  303. lxc.cap.drop = sys_module mac_admin mac_override
  304. lxc.pivotdir = lxc_putold
  305.  
  306. # uncomment the next line to run the container unconfined:
  307. #lxc.aa_profile = unconfined
  308.  
  309. lxc.cgroup.devices.deny = a
  310. # Allow any mknod (but not using the node)
  311. lxc.cgroup.devices.allow = c *:* m
  312. lxc.cgroup.devices.allow = b *:* m
  313. # /dev/null and zero
  314. lxc.cgroup.devices.allow = c 1:3 rwm
  315. lxc.cgroup.devices.allow = c 1:5 rwm
  316. # consoles
  317. lxc.cgroup.devices.allow = c 5:1 rwm
  318. lxc.cgroup.devices.allow = c 5:0 rwm
  319. #lxc.cgroup.devices.allow = c 4:0 rwm
  320. #lxc.cgroup.devices.allow = c 4:1 rwm
  321. # /dev/{,u}random
  322. lxc.cgroup.devices.allow = c 1:9 rwm
  323. lxc.cgroup.devices.allow = c 1:8 rwm
  324. lxc.cgroup.devices.allow = c 136:* rwm
  325. lxc.cgroup.devices.allow = c 5:2 rwm
  326. # rtc
  327. lxc.cgroup.devices.allow = c 254:0 rwm
  328. #fuse
  329. lxc.cgroup.devices.allow = c 10:229 rwm
  330. #tun
  331. lxc.cgroup.devices.allow = c 10:200 rwm
  332. #full
  333. lxc.cgroup.devices.allow = c 1:7 rwm
  334. #hpet
  335. lxc.cgroup.devices.allow = c 10:228 rwm
  336. #kvm
  337. lxc.cgroup.devices.allow = c 10:232 rwm
  338. EOF
  339.  
  340.     cat <<EOF > $path/fstab
  341. proc            proc         proc    nodev,noexec,nosuid 0 0
  342. sysfs           sys          sysfs defaults  0 0
  343. EOF
  344.  
  345.     if [ $? -ne 0 ]; then
  346.         echo "Failed to add configuration"
  347.         return 1
  348.     fi
  349.  
  350.     return 0
  351. }
  352.  
  353. trim()
  354. {
  355.     rootfs=$1
  356.     release=$2
  357.  
  358.     # provide the lxc service
  359.     cat <<EOF > $rootfs/etc/init/lxc.conf
  360. # fake some events needed for correct startup other services
  361.  
  362. description     "Container Upstart"
  363.  
  364. start on startup
  365.  
  366. script
  367.         rm -rf /var/run/*.pid
  368.         rm -rf /var/run/network/*
  369.         /sbin/initctl emit stopped JOB=udevtrigger --no-wait
  370.         /sbin/initctl emit started JOB=udev --no-wait
  371. end script
  372. EOF
  373.  
  374.     # fix buggus runlevel with sshd
  375.     cat <<EOF > $rootfs/etc/init/ssh.conf
  376. # ssh - OpenBSD Secure Shell server
  377. #
  378. # The OpenSSH server provides secure shell access to the system.
  379.  
  380. description "OpenSSH server"
  381.  
  382. start on filesystem
  383. stop on runlevel [!2345]
  384.  
  385. expect fork
  386. respawn
  387. respawn limit 10 5
  388. umask 022
  389. # replaces SSHD_OOM_ADJUST in /etc/default/ssh
  390. oom never
  391.  
  392. pre-start script
  393.     test -x /usr/sbin/sshd || { stop; exit 0; }
  394.     test -e /etc/ssh/sshd_not_to_be_run && { stop; exit 0; }
  395.     test -c /dev/null || { stop; exit 0; }
  396.  
  397.     mkdir -p -m0755 /var/run/sshd
  398. end script
  399.  
  400. # if you used to set SSHD_OPTS in /etc/default/ssh, you can change the
  401. # 'exec' line here instead
  402. exec /usr/sbin/sshd
  403. EOF
  404.  
  405.     cat <<EOF > $rootfs/etc/init/console.conf
  406. # console - getty
  407. #
  408. # This service maintains a console on tty1 from the point the system is
  409. # started until it is shut down again.
  410.  
  411. start on stopped rc RUNLEVEL=[2345]
  412. stop on runlevel [!2345]
  413.  
  414. respawn
  415. exec /sbin/getty -8 38400 /dev/console
  416. EOF
  417.  
  418.     cat <<EOF > $rootfs/lib/init/fstab
  419. # /lib/init/fstab: cleared out for bare-bones lxc
  420. EOF
  421.  
  422.     # reconfigure some services
  423.     if [ -z "$LANG" ]; then
  424.         chroot $rootfs locale-gen en_US.UTF-8
  425.         chroot $rootfs update-locale LANG=en_US.UTF-8
  426.     else
  427.         chroot $rootfs locale-gen $LANG
  428.         chroot $rootfs update-locale LANG=$LANG
  429.     fi
  430.  
  431.     # remove pointless services in a container
  432.     chroot $rootfs /usr/sbin/update-rc.d -f ondemand remove
  433.  
  434.     chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls u*.conf); do mv $f $f.orig; done'
  435.     chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls tty[2-9].conf); do mv $f $f.orig; done'
  436.     chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls plymouth*.conf); do mv $f $f.orig; done'
  437.     chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls hwclock*.conf); do mv $f $f.orig; done'
  438.     chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls module*.conf); do mv $f $f.orig; done'
  439.  
  440.     # if this isn't lucid, then we need to twiddle the network upstart bits :(
  441.     if [ $release != "lucid" ]; then
  442.         sed -i 's/^.*emission handled.*$/echo Emitting lo/' $rootfs/etc/network/if-up.d/upstart
  443.     fi
  444. }
  445.  
  446. post_process()
  447. {
  448.     rootfs=$1
  449.     release=$2
  450.     trim_container=$3
  451.  
  452.     if [ $trim_container -eq 1 ]; then
  453.         trim $rootfs $release
  454.     elif [ ! -f $rootfs/etc/init/container-detect.conf ]; then
  455.         # Make sure we have a working resolv.conf
  456.         cresolvonf="${rootfs}/etc/resolv.conf"
  457.         mv $cresolvonf ${cresolvonf}.lxcbak
  458.         cat /etc/resolv.conf > ${cresolvonf}
  459.  
  460.         # for lucid, if not trimming, then add the ubuntu-virt
  461.         # ppa and install lxcguest
  462.         if [ $release = "lucid" ]; then
  463.             chroot $rootfs apt-get install --force-yes -y python-software-properties
  464.             chroot $rootfs add-apt-repository ppa:ubuntu-virt/ppa
  465.         fi
  466.  
  467.         chroot $rootfs apt-get update
  468.         chroot $rootfs apt-get install --force-yes -y lxcguest
  469.  
  470.         # Restore old resolv.conf
  471.         rm -f ${cresolvonf}
  472.         mv ${cresolvonf}.lxcbak ${cresolvonf}
  473.     fi
  474.  
  475.     # If the container isn't running a native architecture, setup multiarch
  476.     if [ -x "$(ls -1 ${rootfs}/usr/bin/qemu-*-static 2>/dev/null)" ]; then
  477.         dpkg_version=$(chroot $rootfs dpkg-query -W -f='${Version}' dpkg)
  478.         if chroot $rootfs dpkg --compare-versions $dpkg_version ge "1.16.2"; then
  479.             chroot $rootfs dpkg --add-architecture ${hostarch}
  480.         else
  481.             mkdir -p ${rootfs}/etc/dpkg/dpkg.cfg.d
  482.             echo "foreign-architecture ${hostarch}" > ${rootfs}/etc/dpkg/dpkg.cfg.d/lxc-multiarch
  483.         fi
  484.  
  485.         # Save existing value of MIRROR and SECURITY_MIRROR
  486.         DEFAULT_MIRROR=$MIRROR
  487.         DEFAULT_SECURITY_MIRROR=$SECURITY_MIRROR
  488.  
  489.         # Write a new sources.list containing both native and multiarch entries
  490.         > ${rootfs}/etc/apt/sources.list
  491.         write_sourceslist $rootfs $arch "native"
  492.  
  493.         MIRROR=$DEFAULT_MIRROR
  494.         SECURITY_MIRROR=$DEFAULT_SECURITY_MIRROR
  495.         write_sourceslist $rootfs $hostarch "multiarch"
  496.  
  497.         # Finally update the lists and install upstart using the host architecture
  498.         chroot $rootfs apt-get update
  499.         chroot $rootfs apt-get install --force-yes -y --no-install-recommends upstart:${hostarch} mountall:${hostarch} iproute:${hostarch} isc-dhcp-client:${hostarch}
  500.     fi
  501.  
  502.     # rmdir /dev/shm for containers that have /run/shm
  503.     # I'm afraid of doing rm -rf $rootfs/dev/shm, in case it did
  504.     # get bind mounted to the host's /run/shm.  So try to rmdir
  505.     # it, and in case that fails move it out of the way.
  506.     if [ -d $rootfs/run/shm ]; then
  507.         [ -d "$rootfs/dev/shm" ] && rmdir $rootfs/dev/shm
  508.         [ -e "$rootfs/dev/shm" ] && mv $rootfs/dev/shm $rootfs/dev/shm.bak
  509.         ln -s /run/shm $rootfs/dev/shm
  510.     fi
  511. }
  512.  
  513. do_bindhome()
  514. {
  515.     rootfs=$1
  516.     user=$2
  517.  
  518.     # copy /etc/passwd, /etc/shadow, and /etc/group entries into container
  519.     pwd=`getent passwd $user` || { echo "Failed to copy password entry for $user"; false; }
  520.     echo $pwd >> $rootfs/etc/passwd
  521.  
  522.     # make sure user's shell exists in the container
  523.     shell=`echo $pwd | cut -d: -f 7`
  524.     if [ ! -x $rootfs/$shell ]; then
  525.         echo "shell $shell for user $user was not found in the container."
  526.         pkg=`dpkg -S $(readlink -m $shell) | cut -d ':' -f1`
  527.         echo "Installing $pkg"
  528.         chroot $rootfs apt-get --force-yes -y install $pkg
  529.     fi
  530.  
  531.     shad=`getent shadow $user`
  532.     echo "$shad" >> $rootfs/etc/shadow
  533.  
  534.     # bind-mount the user's path into the container's /home
  535.     h=`getent passwd $user | cut -d: -f 6`
  536.     mkdir -p $rootfs/$h
  537.  
  538.     # use relative path in container
  539.     h2=${h#/}
  540.     while [ ${h2:0:1} = "/" ]; do
  541.         h2=${h2#/}
  542.     done
  543.     echo "$h $h2 none bind 0 0" >> $path/fstab
  544.  
  545.     # Make sure the group exists in container
  546.     grp=`echo $pwd | cut -d: -f 4`  # group number for $user
  547.     grpe=`getent group $grp` || return 0  # if host doesn't define grp, ignore in container
  548.     chroot $rootfs getent group "$grpe" || echo "$grpe" >> $rootfs/etc/group
  549. }
  550.  
  551. usage()
  552. {
  553.     cat <<EOF
  554. $1 -h|--help [-a|--arch] [-b|--bindhome <user>] [--trim] [-d|--debug]
  555.    [-F | --flush-cache] [-r|--release <release>] [ -S | --auth-key <keyfile>]
  556. release: the ubuntu release (e.g. precise): defaults to host release on ubuntu, otherwise uses latest LTS
  557. trim: make a minimal (faster, but not upgrade-safe) container
  558. bindhome: bind <user>'s home into the container
  559.           The ubuntu user will not be created, and <user> will have
  560.           sudo access.
  561. arch: the container architecture (e.g. amd64): defaults to host arch
  562. auth-key: SSH Public key file to inject into container
  563. EOF
  564.     return 0
  565. }
  566.  
  567. options=$(getopt -o a:b:hp:r:xn:FS:d -l arch:,bindhome:,help,path:,release:,trim,name:,flush-cache,auth-key:,debug -- "$@")
  568. if [ $? -ne 0 ]; then
  569.     usage $(basename $0)
  570.     exit 1
  571. fi
  572. eval set -- "$options"
  573.  
  574. release=precise # Default to the last Ubuntu LTS release for non-Ubuntu systems
  575. if [ -f /etc/lsb-release ]; then
  576.     . /etc/lsb-release
  577.     if [ "$DISTRIB_ID" = "Ubuntu" ]; then
  578.         release=$DISTRIB_CODENAME
  579.     fi
  580. fi
  581.  
  582. bindhome=
  583. arch=$(uname -m)
  584.  
  585. # Code taken from debootstrap
  586. if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
  587.     arch=`/usr/bin/dpkg --print-architecture`
  588. elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
  589.     arch=`/usr/bin/udpkg --print-architecture`
  590. else
  591.     arch=$(uname -m)
  592.     if [ "$arch" = "i686" ]; then
  593.         arch="i386"
  594.     elif [ "$arch" = "x86_64" ]; then
  595.         arch="amd64"
  596.     elif [ "$arch" = "armv7l" ]; then
  597.         arch="armel"
  598.     fi
  599. fi
  600.  
  601. debug=0
  602. trim_container=0
  603. hostarch=$arch
  604. flushcache=0
  605. while true
  606. do
  607.     case "$1" in
  608.     -h|--help)      usage $0 && exit 0;;
  609.     -p|--path)      path=$2; shift 2;;
  610.     -n|--name)      name=$2; shift 2;;
  611.     -F|--flush-cache) flushcache=1; shift 1;;
  612.     -r|--release)   release=$2; shift 2;;
  613.     -b|--bindhome)  bindhome=$2; shift 2;;
  614.     -a|--arch)      arch=$2; shift 2;;
  615.     -x|--trim)      trim_container=1; shift 1;;
  616.     -S|--auth-key)  auth_key=$2; shift 2;;
  617.     -d|--debug)     debug=1; shift 1;;
  618.     --)             shift 1; break ;;
  619.         *)              break ;;
  620.     esac
  621. done
  622.  
  623. if [ $debug -eq 1 ]; then
  624.     set -x
  625. fi
  626.  
  627. if [ -n "$bindhome" ]; then
  628.     pwd=`getent passwd $bindhome`
  629.     if [ $? -ne 0 ]; then
  630.         echo "Error: no password entry found for $bindhome"
  631.         exit 1
  632.     fi
  633. fi
  634.  
  635.  
  636. if [ "$arch" == "i686" ]; then
  637.     arch=i386
  638. fi
  639.  
  640. if [ $hostarch = "i386" -a $arch = "amd64" ]; then
  641.     echo "can't create amd64 container on i386"
  642.     exit 1
  643. fi
  644.  
  645. type debootstrap
  646. if [ $? -ne 0 ]; then
  647.     echo "'debootstrap' command is missing"
  648.     exit 1
  649. fi
  650.  
  651. if [ -z "$path" ]; then
  652.     echo "'path' parameter is required"
  653.     exit 1
  654. fi
  655.  
  656. if [ "$(id -u)" != "0" ]; then
  657.     echo "This script should be run as 'root'"
  658.     exit 1
  659. fi
  660.  
  661. rootfs=$path/rootfs
  662.  
  663. install_ubuntu $rootfs $release $flushcache
  664. if [ $? -ne 0 ]; then
  665.     echo "failed to install ubuntu $release"
  666.     exit 1
  667. fi
  668.  
  669. configure_ubuntu $rootfs $name $release
  670. if [ $? -ne 0 ]; then
  671.     echo "failed to configure ubuntu $release for a container"
  672.     exit 1
  673. fi
  674.  
  675. copy_configuration $path $rootfs $name $arch $release
  676. if [ $? -ne 0 ]; then
  677.     echo "failed write configuration file"
  678.     exit 1
  679. fi
  680.  
  681. post_process $rootfs $release $trim_container
  682.  
  683. if [ -n "$bindhome" ]; then
  684.     do_bindhome $rootfs $bindhome
  685.     finalize_user $bindhome
  686. else
  687.     finalize_user ubuntu
  688. fi
  689.  
  690. echo ""
  691. echo "##"
  692. echo "# The default user is 'ubuntu' with password 'ubuntu'!"
  693. echo "# Use the 'sudo' command to run tasks as root in the container."
  694. echo "##"
  695. echo ""