4
# template script for generating ubuntu container for LXC
6
# This script consolidates and extends the existing lxc ubuntu scripts
9
# Copyright � 2011 Serge Hallyn <serge.hallyn@canonical.com>
10
# Copyright � 2010 Wilhelm Meier
11
# Author: Wilhelm Meier <wilhelm.meier@fh-kl.de>
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.
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.
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.
29
if [ -r /etc/default/lxc ]; then
38
# configure the network using the dhcp
39
cat <<EOF > $rootfs/etc/network/interfaces
41
iface lo inet loopback
47
# so you can 'ssh $hostname.' or 'ssh $hostname.local'
48
if [ -f $rootfs/etc/dhcp/dhclient.conf ]; then
49
sed -i "s/<hostname>/$hostname/" $rootfs/etc/dhcp/dhclient.conf
50
elif [ -f $rootfs/etc/dhcp3/dhclient.conf ]; then
51
sed -i "s/<hostname>/$hostname/" $rootfs/etc/dhcp3/dhclient.conf
55
cat <<EOF > $rootfs/etc/hostname
59
cat <<EOF > $rootfs/etc/hosts
60
127.0.0.1 localhost $hostname
63
# suppress log level output for udev
64
sed -i "s/=\"err\"/=0/" $rootfs/etc/udev/udev.conf
66
# remove jobs for consoles 5 and 6 since we only create 4 consoles in
68
rm -f $rootfs/etc/init/tty{5,6}.conf
70
echo "Please change root-password !"
71
echo "root:root" | chroot $rootfs chpasswd
78
# $1 => path to the rootfs
79
# $2 => architecture we want to add
80
# $3 => whether to use the multi-arch syntax or not
84
MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu}
85
SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.ubuntu.com/ubuntu}
90
MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu}
91
SECURITY_MIRROR=${SECURITY_MIRRORMIRROR:-http://security.ubuntu.com/ubuntu}
94
MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
95
SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
100
MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
101
SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
105
cat >> "$1/etc/apt/sources.list" << EOF
106
deb [arch=$2] $MIRROR ${release} main restricted universe multiverse
107
deb [arch=$2] $MIRROR ${release}-updates main restricted universe multiverse
108
deb [arch=$2] $SECURITY_MIRROR ${release}-security main restricted universe multiverse
111
cat >> "$1/etc/apt/sources.list" << EOF
112
deb $MIRROR ${release} main restricted universe multiverse
113
deb $MIRROR ${release}-updates main restricted universe multiverse
114
deb $SECURITY_MIRROR ${release}-security main restricted universe multiverse
125
if [ $release = "lucid" ]; then
126
packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,dhcp3-client,ssh,lsb-release,gnupg
127
elif [ $release = "maverick" ]; then
128
packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,dhcp3-client,ssh,lsb-release,gnupg,netbase
129
elif [ $release = "natty" ]; then
130
packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,isc-dhcp-client,isc-dhcp-common,ssh,lsb-release,gnupg,netbase
132
packages=dialog,apt,apt-utils,iproute,inetutils-ping,vim,isc-dhcp-client,isc-dhcp-common,ssh,lsb-release,gnupg,netbase,ubuntu-keyring
134
echo "installing packages: $packages"
136
# check the mini ubuntu was not already downloaded
137
mkdir -p "$cache/partial-$arch"
138
if [ $? -ne 0 ]; then
139
echo "Failed to create '$cache/partial-$arch' directory"
143
# download a mini ubuntu into a cache
144
echo "Downloading ubuntu $release minimal ..."
145
if [ -n "$(which qemu-debootstrap)" ]; then
146
qemu-debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
148
debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
151
if [ $? -ne 0 ]; then
152
echo "Failed to download the rootfs, aborting."
156
# Serge isn't sure whether we should avoid doing this when
157
# $release == `distro-info -d`
158
echo "Installing updates"
159
> $cache/partial-$arch/etc/apt/sources.list
160
write_sourceslist $cache/partial-$arch/ $arch
162
chroot "$1/partial-${arch}" apt-get update
163
if [ $? -ne 0 ]; then
164
echo "Failed to update the apt cache"
167
cat > "$1/partial-${arch}"/usr/sbin/policy-rc.d << EOF
171
chmod +x "$1/partial-${arch}"/usr/sbin/policy-rc.d
173
lxc-unshare -s MOUNT -- chroot "$1/partial-${arch}" apt-get dist-upgrade -y
175
rm -f "$1/partial-${arch}"/usr/sbin/policy-rc.d
177
if [ $ret -ne 0 ]; then
178
echo "Failed to upgrade the cache"
182
mv "$1/partial-$arch" "$1/rootfs-$arch"
183
echo "Download complete"
193
# make a local copy of the miniubuntu
194
echo -n "Copying rootfs to $rootfs ..."
196
rsync -a $cache/rootfs-$arch/ $rootfs/ || return 1
205
cache="/var/cache/lxc/$release"
206
mkdir -p /var/lock/subsys/
209
if [ $? -ne 0 ]; then
210
echo "Cache repository is busy."
215
if [ $flushcache -eq 1 ]; then
216
echo "Flushing cache..."
217
rm -rf "$cache/partial-$arch"
218
rm -rf "$cache/rootfs-$arch"
221
echo "Checking cache download in $cache/rootfs-$arch ... "
222
if [ ! -e "$cache/rootfs-$arch" ]; then
223
download_ubuntu $cache $arch $release
224
if [ $? -ne 0 ]; then
225
echo "Failed to download 'ubuntu $release base'"
230
echo "Copy $cache/rootfs-$arch to $rootfs ... "
231
copy_ubuntu $cache $arch $rootfs
232
if [ $? -ne 0 ]; then
233
echo "Failed to copy rootfs"
239
) 200>/var/lock/subsys/lxc
251
if [ $arch = "i386" ]; then
255
cat <<EOF >> $path/config
261
lxc.mount = $path/fstab
263
lxc.cap.drop = sys_module mac_admin
265
lxc.cgroup.devices.deny = a
266
# Allow any mknod (but not using the node)
267
lxc.cgroup.devices.allow = c *:* m
268
lxc.cgroup.devices.allow = b *:* m
270
lxc.cgroup.devices.allow = c 1:3 rwm
271
lxc.cgroup.devices.allow = c 1:5 rwm
273
lxc.cgroup.devices.allow = c 5:1 rwm
274
lxc.cgroup.devices.allow = c 5:0 rwm
275
#lxc.cgroup.devices.allow = c 4:0 rwm
276
#lxc.cgroup.devices.allow = c 4:1 rwm
278
lxc.cgroup.devices.allow = c 1:9 rwm
279
lxc.cgroup.devices.allow = c 1:8 rwm
280
lxc.cgroup.devices.allow = c 136:* rwm
281
lxc.cgroup.devices.allow = c 5:2 rwm
283
lxc.cgroup.devices.allow = c 254:0 rwm
285
lxc.cgroup.devices.allow = c 10:229 rwm
287
lxc.cgroup.devices.allow = c 10:200 rwm
289
lxc.cgroup.devices.allow = c 1:7 rwm
291
lxc.cgroup.devices.allow = c 10:228 rwm
293
lxc.cgroup.devices.allow = c 10:232 rwm
296
cat <<EOF > $path/fstab
297
proc $rootfs/proc proc nodev,noexec,nosuid 0 0
298
sysfs $rootfs/sys sysfs defaults 0 0
301
if [ $? -ne 0 ]; then
302
echo "Failed to add configuration"
314
# provide the lxc service
315
cat <<EOF > $rootfs/etc/init/lxc.conf
316
# fake some events needed for correct startup other services
318
description "Container Upstart"
323
rm -rf /var/run/*.pid
324
rm -rf /var/run/network/*
325
/sbin/initctl emit stopped JOB=udevtrigger --no-wait
326
/sbin/initctl emit started JOB=udev --no-wait
330
# fix buggus runlevel with sshd
331
cat <<EOF > $rootfs/etc/init/ssh.conf
332
# ssh - OpenBSD Secure Shell server
334
# The OpenSSH server provides secure shell access to the system.
336
description "OpenSSH server"
339
stop on runlevel [!2345]
345
# replaces SSHD_OOM_ADJUST in /etc/default/ssh
349
test -x /usr/sbin/sshd || { stop; exit 0; }
350
test -e /etc/ssh/sshd_not_to_be_run && { stop; exit 0; }
351
test -c /dev/null || { stop; exit 0; }
353
mkdir -p -m0755 /var/run/sshd
356
# if you used to set SSHD_OPTS in /etc/default/ssh, you can change the
357
# 'exec' line here instead
361
cat <<EOF > $rootfs/etc/init/console.conf
364
# This service maintains a console on tty1 from the point the system is
365
# started until it is shut down again.
367
start on stopped rc RUNLEVEL=[2345]
368
stop on runlevel [!2345]
371
exec /sbin/getty -8 38400 /dev/console
374
cat <<EOF > $rootfs/lib/init/fstab
375
# /lib/init/fstab: cleared out for bare-bones lxc
378
# reconfigure some services
379
if [ -z "$LANG" ]; then
380
chroot $rootfs locale-gen en_US.UTF-8
381
chroot $rootfs update-locale LANG=en_US.UTF-8
383
chroot $rootfs locale-gen $LANG
384
chroot $rootfs update-locale LANG=$LANG
387
# remove pointless services in a container
388
chroot $rootfs /usr/sbin/update-rc.d -f ondemand remove
390
chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls u*.conf); do mv $f $f.orig; done'
391
chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls tty[2-9].conf); do mv $f $f.orig; done'
392
chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls plymouth*.conf); do mv $f $f.orig; done'
393
chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls hwclock*.conf); do mv $f $f.orig; done'
394
chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls module*.conf); do mv $f $f.orig; done'
396
# if this isn't lucid, then we need to twiddle the network upstart bits :(
397
if [ $release != "lucid" ]; then
398
sed -i 's/^.*emission handled.*$/echo Emitting lo/' $rootfs/etc/network/if-up.d/upstart
408
if [ $trim_container -eq 1 ]; then
409
trim $rootfs $release
410
elif [ $release = "lucid" -o $release = "maverick" -o $release = "natty" \
411
-o $release = "oneiric" ]; then
412
# for lucid and maverick, if not trimming, then add the ubuntu-virt
413
# ppa and install lxcguest
414
if [ $release = "lucid" -o $release = "maverick" ]; then
415
chroot $rootfs apt-get install --force-yes -y python-software-properties
416
chroot $rootfs add-apt-repository ppa:ubuntu-virt/ppa
418
cresolvonf="${rootfs}/etc/resolv.conf"
419
mv $cresolvonf ${cresolvonf}.lxcbak
420
cat /etc/resolv.conf > ${cresolvonf}
421
chroot $rootfs apt-get update
422
chroot $rootfs apt-get install --force-yes -y lxcguest
424
mv ${cresolvonf}.lxcbak ${cresolvonf}
427
# If the container isn't running a native architecture, setup multiarch
428
if [ -x "$(ls -1 ${rootfs}/usr/bin/qemu-*-static 2>/dev/null)" ]; then
429
mkdir -p ${rootfs}/etc/dpkg/dpkg.cfg.d
430
echo "foreign-architecture ${hostarch}" > ${rootfs}/etc/dpkg/dpkg.cfg.d/lxc-multiarch
432
# Save existing value of MIRROR and SECURITY_MIRROR
433
DEFAULT_MIRROR=$MIRROR
434
DEFAULT_SECURITY_MIRROR=$SECURITY_MIRROR
436
# Write a new sources.list containing both native and multiarch entries
437
> ${rootfs}/etc/apt/sources.list
438
write_sourceslist $rootfs $arch "native"
440
MIRROR=$DEFAULT_MIRROR
441
SECURITY_MIRROR=$DEFAULT_SECURITY_MIRROR
442
write_sourceslist $rootfs $hostarch "multiarch"
444
# Finally update the lists and install upstart using the host architecture
445
chroot $rootfs apt-get update
446
chroot $rootfs apt-get install --force-yes -y --no-install-recommends upstart:${hostarch} mountall:amd64 iproute:amd64 isc-dhcp-client:amd64
455
# copy /etc/passwd, /etc/shadow, and /etc/group entries into container
456
pwd=`getent passwd $user`
457
if [ $? -ne 0 ]; then
458
echo 'Warning: failed to copy password entry for $user'
461
echo $pwd >> $rootfs/etc/passwd
463
shad=`getent shadow $user`
464
echo $shad >> $rootfs/etc/shadow
466
# bind-mount the user's path into the container's /home
467
h=`getent passwd $user | cut -d: -f 6`
469
echo "$h $rootfs/$h none bind 0 0" >> $path/fstab
475
$1 -h|--help [-a|--arch] [-b|--bindhome <user>] [--trim]
476
[-F | --flush-cache] [-r|--release <release>]
477
release: lucid | maverick | natty | oneiric | precise
478
trim: make a minimal (faster, but not upgrade-safe) container
479
bindhome: bind <user>'s home into the container
480
arch: amd64 or i386: defaults to host arch
485
options=$(getopt -o a:b:hp:r:xn:F -l arch:,bindhome:,help,path:,release:,trim,name:,flush-cache -- "$@")
486
if [ $? -ne 0 ]; then
490
eval set -- "$options"
493
if [ -f /etc/lsb-release ]; then
495
case "$DISTRIB_CODENAME" in
496
lucid|maverick|natty|oneiric|precise)
497
release=$DISTRIB_CODENAME
505
# Code taken from debootstrap
506
if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
507
arch=`/usr/bin/dpkg --print-architecture`
508
elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
509
arch=`/usr/bin/udpkg --print-architecture`
512
if [ "$arch" = "i686" ]; then
514
elif [ "$arch" = "x86_64" ]; then
516
elif [ "$arch" = "armv7l" ]; then
527
-h|--help) usage $0 && exit 0;;
528
-p|--path) path=$2; shift 2;;
529
-n|--name) name=$2; shift 2;;
530
-F|--flush-cache) flushcache=1; shift 1;;
531
-r|--release) release=$2; shift 2;;
532
-b|--bindhome) bindhome=$2; shift 2;;
533
-a|--arch) arch=$2; shift 2;;
534
-x|--trim) trim_container=1; shift 1;;
535
--) shift 1; break ;;
540
pwd=`getent passwd $bindhome`
541
if [ $? -ne 0 ]; then
542
echo "Error: no password entry found for $bindhome"
547
if [ "$arch" == "i686" ]; then
551
if [ $hostarch = "i386" -a $arch = "amd64" ]; then
552
echo "can't create amd64 container on i386"
557
if [ $? -ne 0 ]; then
558
echo "'debootstrap' command is missing"
562
if [ -z "$path" ]; then
563
echo "'path' parameter is required"
567
if [ "$(id -u)" != "0" ]; then
568
echo "This script should be run as 'root'"
574
install_ubuntu $rootfs $release $flushcache
575
if [ $? -ne 0 ]; then
576
echo "failed to install ubuntu $release"
580
configure_ubuntu $rootfs $name
581
if [ $? -ne 0 ]; then
582
echo "failed to configure ubuntu $release for a container"
586
copy_configuration $path $rootfs $name $arch
587
if [ $? -ne 0 ]; then
588
echo "failed write configuration file"
592
post_process $rootfs $release $trim_container
593
if [ ! -z $bindhome ]; then
594
do_bindhome $rootfs $bindhome