~ubuntu-branches/ubuntu/quantal/lxc/quantal-201206191543

« back to all changes in this revision

Viewing changes to templates/lxc-ubuntu.in

  • Committer: Stéphane Graber
  • Date: 2011-08-11 18:43:51 UTC
  • mto: (3.1.15 sid)
  • mto: This revision was merged to the branch mainline in revision 30.
  • Revision ID: stgraber@ubuntu.com-20110811184351-xa4c5v0ct5ud45d0
Tags: upstream-0.7.5
Import upstream version 0.7.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
# XXX todo: add -lvm option
 
10
 
 
11
# Copyright � 2011 Serge Hallyn <serge.hallyn@canonical.com>
 
12
# Copyright � 2010 Wilhelm Meier
 
13
# Author: Wilhelm Meier <wilhelm.meier@fh-kl.de>
 
14
#
 
15
# This program is free software; you can redistribute it and/or modify
 
16
# it under the terms of the GNU General Public License version 2, as
 
17
# published by the Free Software Foundation.
 
18
 
 
19
# This program is distributed in the hope that it will be useful,
 
20
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
# GNU General Public License for more details.
 
23
 
 
24
# You should have received a copy of the GNU General Public License along
 
25
# with this program; if not, write to the Free Software Foundation, Inc.,
 
26
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
27
#
 
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
 
 
38
   # configure the network using the dhcp
 
39
    cat <<EOF > $rootfs/etc/network/interfaces
 
40
auto lo
 
41
iface lo inet loopback
 
42
 
 
43
auto eth0
 
44
iface eth0 inet dhcp
 
45
EOF
 
46
 
 
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
 
52
    fi
 
53
 
 
54
    # set the hostname
 
55
    cat <<EOF > $rootfs/etc/hostname
 
56
$hostname
 
57
EOF
 
58
    # set minimal hosts
 
59
    cat <<EOF > $rootfs/etc/hosts
 
60
127.0.0.1 localhost $hostname
 
61
EOF
 
62
 
 
63
    # suppress log level output for udev
 
64
    sed -i "s/=\"err\"/=0/" $rootfs/etc/udev/udev.conf
 
65
 
 
66
    # remove jobs for consoles 5 and 6 since we only create 4 consoles in
 
67
    # this template
 
68
    rm -f $rootfs/etc/init/tty{5,6}.conf
 
69
 
 
70
    echo "Please change root-password !"
 
71
    echo "root:root" | chroot $rootfs chpasswd
 
72
 
 
73
    return 0
 
74
}
 
75
 
 
76
download_ubuntu()
 
77
{
 
78
    cache=$1
 
79
    arch=$2
 
80
    release=$3
 
81
 
 
82
    if [ $release = "lucid" ]; then
 
83
        packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,dhcp3-client,ssh,lsb-release,gnupg
 
84
    elif [ $release = "maverick" ]; then
 
85
        packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,dhcp3-client,ssh,lsb-release,gnupg,netbase
 
86
    elif [ $release = "natty" ]; then
 
87
        packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,isc-dhcp-client,isc-dhcp-common,ssh,lsb-release,gnupg,netbase
 
88
    else
 
89
        packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,isc-dhcp-client,isc-dhcp-common,ssh,lsb-release,gnupg,netbase,ubuntu-keyring
 
90
    fi
 
91
    echo "installing packages: $packages"
 
92
 
 
93
    # check the mini ubuntu was not already downloaded
 
94
    mkdir -p "$cache/partial-$arch"
 
95
    if [ $? -ne 0 ]; then
 
96
        echo "Failed to create '$cache/partial-$arch' directory"
 
97
        return 1
 
98
    fi
 
99
 
 
100
    # download a mini ubuntu into a cache
 
101
    echo "Downloading ubuntu $release minimal ..."
 
102
    debootstrap --verbose --variant=minbase --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
 
103
    if [ $? -ne 0 ]; then
 
104
        echo "Failed to download the rootfs, aborting."
 
105
            return 1
 
106
    fi
 
107
 
 
108
    mv "$1/partial-$arch" "$1/rootfs-$arch"
 
109
    echo "Download complete."
 
110
 
 
111
    return 0
 
112
}
 
113
 
 
114
copy_ubuntu()
 
115
{
 
116
    cache=$1
 
117
    arch=$2
 
118
    rootfs=$3
 
119
 
 
120
    # make a local copy of the miniubuntu
 
121
    echo -n "Copying rootfs to $rootfs ..."
 
122
    cp -a $cache/rootfs-$arch $rootfs || return 1
 
123
    return 0
 
124
}
 
125
 
 
126
install_ubuntu()
 
127
{
 
128
    rootfs=$1
 
129
    release=$2
 
130
    cache="/var/cache/lxc/$release"
 
131
    mkdir -p /var/lock/subsys/
 
132
    (
 
133
        flock -n -x 200
 
134
        if [ $? -ne 0 ]; then
 
135
            echo "Cache repository is busy."
 
136
            return 1
 
137
        fi
 
138
 
 
139
 
 
140
        echo "Checking cache download in $cache/rootfs-$arch ... "
 
141
        if [ ! -e "$cache/rootfs-$arch" ]; then
 
142
            download_ubuntu $cache $arch $release
 
143
            if [ $? -ne 0 ]; then
 
144
                echo "Failed to download 'ubuntu $release base'"
 
145
                return 1
 
146
            fi
 
147
        fi
 
148
 
 
149
        echo "Copy $cache/rootfs-$arch to $rootfs ... "
 
150
        copy_ubuntu $cache $arch $rootfs
 
151
        if [ $? -ne 0 ]; then
 
152
            echo "Failed to copy rootfs"
 
153
            return 1
 
154
        fi
 
155
 
 
156
        return 0
 
157
 
 
158
        ) 200>/var/lock/subsys/lxc
 
159
 
 
160
    return $?
 
161
}
 
162
 
 
163
copy_configuration()
 
164
{
 
165
    path=$1
 
166
    rootfs=$2
 
167
    name=$3
 
168
    arch=$4
 
169
 
 
170
    if [ $arch = "i386" ]; then
 
171
        arch="i686"
 
172
    fi
 
173
 
 
174
    cat <<EOF >> $path/config
 
175
lxc.utsname = $name
 
176
 
 
177
lxc.tty = 4
 
178
lxc.pts = 1024
 
179
lxc.rootfs = $rootfs
 
180
lxc.mount  = $path/fstab
 
181
lxc.arch = $arch
 
182
 
 
183
lxc.cgroup.devices.deny = a
 
184
# /dev/null and zero
 
185
lxc.cgroup.devices.allow = c 1:3 rwm
 
186
lxc.cgroup.devices.allow = c 1:5 rwm
 
187
# consoles
 
188
lxc.cgroup.devices.allow = c 5:1 rwm
 
189
lxc.cgroup.devices.allow = c 5:0 rwm
 
190
#lxc.cgroup.devices.allow = c 4:0 rwm
 
191
#lxc.cgroup.devices.allow = c 4:1 rwm
 
192
# /dev/{,u}random
 
193
lxc.cgroup.devices.allow = c 1:9 rwm
 
194
lxc.cgroup.devices.allow = c 1:8 rwm
 
195
lxc.cgroup.devices.allow = c 136:* rwm
 
196
lxc.cgroup.devices.allow = c 5:2 rwm
 
197
# rtc
 
198
lxc.cgroup.devices.allow = c 254:0 rwm
 
199
#fuse
 
200
lxc.cgroup.devices.allow = c 10:229 rwm
 
201
EOF
 
202
 
 
203
    cat <<EOF > $path/fstab
 
204
proc            $rootfs/proc         proc    nodev,noexec,nosuid 0 0
 
205
sysfs           $rootfs/sys          sysfs defaults  0 0
 
206
EOF
 
207
 
 
208
    if [ $? -ne 0 ]; then
 
209
        echo "Failed to add configuration"
 
210
        return 1
 
211
    fi
 
212
 
 
213
    return 0
 
214
}
 
215
 
 
216
trim()
 
217
{
 
218
    rootfs=$1
 
219
    release=$2
 
220
 
 
221
    # provide the lxc service
 
222
    cat <<EOF > $rootfs/etc/init/lxc.conf
 
223
# fake some events needed for correct startup other services
 
224
 
 
225
description     "Container Upstart"
 
226
 
 
227
start on startup
 
228
 
 
229
script
 
230
        rm -rf /var/run/*.pid
 
231
        rm -rf /var/run/network/*
 
232
        /sbin/initctl emit stopped JOB=udevtrigger --no-wait
 
233
        /sbin/initctl emit started JOB=udev --no-wait
 
234
end script
 
235
EOF
 
236
 
 
237
    # fix buggus runlevel with sshd
 
238
    cat <<EOF > $rootfs/etc/init/ssh.conf
 
239
# ssh - OpenBSD Secure Shell server
 
240
#
 
241
# The OpenSSH server provides secure shell access to the system.
 
242
 
 
243
description     "OpenSSH server"
 
244
 
 
245
start on filesystem
 
246
stop on runlevel [!2345]
 
247
 
 
248
expect fork
 
249
respawn
 
250
respawn limit 10 5
 
251
umask 022
 
252
# replaces SSHD_OOM_ADJUST in /etc/default/ssh
 
253
oom never
 
254
 
 
255
pre-start script
 
256
    test -x /usr/sbin/sshd || { stop; exit 0; }
 
257
    test -e /etc/ssh/sshd_not_to_be_run && { stop; exit 0; }
 
258
    test -c /dev/null || { stop; exit 0; }
 
259
 
 
260
    mkdir -p -m0755 /var/run/sshd
 
261
end script
 
262
 
 
263
# if you used to set SSHD_OPTS in /etc/default/ssh, you can change the
 
264
# 'exec' line here instead
 
265
exec /usr/sbin/sshd
 
266
EOF
 
267
 
 
268
    cat <<EOF > $rootfs/etc/init/console.conf
 
269
# console - getty
 
270
#
 
271
# This service maintains a console on tty1 from the point the system is
 
272
# started until it is shut down again.
 
273
 
 
274
start on stopped rc RUNLEVEL=[2345]
 
275
stop on runlevel [!2345]
 
276
 
 
277
respawn
 
278
exec /sbin/getty -8 38400 /dev/console
 
279
EOF
 
280
 
 
281
    cat <<EOF > $rootfs/lib/init/fstab
 
282
# /lib/init/fstab: cleared out for bare-bones lxc
 
283
EOF
 
284
 
 
285
    # reconfigure some services
 
286
    if [ -z "$LANG" ]; then
 
287
        chroot $rootfs locale-gen en_US.UTF-8
 
288
        chroot $rootfs update-locale LANG=en_US.UTF-8
 
289
    else
 
290
        chroot $rootfs locale-gen $LANG
 
291
        chroot $rootfs update-locale LANG=$LANG
 
292
    fi
 
293
 
 
294
    # remove pointless services in a container
 
295
    chroot $rootfs /usr/sbin/update-rc.d -f ondemand remove
 
296
 
 
297
    chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls u*.conf); do mv $f $f.orig; done'
 
298
    chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls tty[2-9].conf); do mv $f $f.orig; done'
 
299
    chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls plymouth*.conf); do mv $f $f.orig; done'
 
300
    chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls hwclock*.conf); do mv $f $f.orig; done'
 
301
    chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls module*.conf); do mv $f $f.orig; done'
 
302
 
 
303
    # if this isn't lucid, then we need to twiddle the network upstart bits :(
 
304
    if [ $release != "lucid" ]; then
 
305
        sed -i 's/^.*emission handled.*$/echo Emitting lo/' $rootfs/etc/network/if-up.d/upstart
 
306
    fi
 
307
}
 
308
 
 
309
post_process()
 
310
{
 
311
    rootfs=$1
 
312
    release=$2
 
313
    trim_container=$3
 
314
 
 
315
    if [ $trim_container -eq 1 ]; then
 
316
        trim $rootfs $release
 
317
    else
 
318
        # for lucid and maverick, if not trimming, then add the ubuntu-virt
 
319
        # ppa and install lxcguest
 
320
        if [ $release = "lucid" -o $release = "maverick" ]; then
 
321
            chroot $rootfs apt-get install --force-yes -y python-software-properties
 
322
            chroot $rootfs add-apt-repository ppa:ubuntu-virt/ppa
 
323
            chroot $rootfs apt-get update
 
324
        fi
 
325
        chroot $rootfs apt-get install --force-yes -y lxcguest
 
326
    fi
 
327
}
 
328
 
 
329
do_bindhome()
 
330
{
 
331
    rootfs=$1
 
332
    user=$2
 
333
 
 
334
    # bind-mount the user's path into the container's /home
 
335
    h=`getent passwd $user | cut -d: -f 6`
 
336
    mkdir -p $rootfs/$h
 
337
    echo "$h $rootfs/$h none bind 0 0" >> $path/fstab
 
338
 
 
339
    # copy /etc/passwd, /etc/shadow, and /etc/group entries into container
 
340
    pwd=`getent passwd $user`
 
341
    if [ $? -ne 0 ]; then
 
342
        echo 'Warning: failed to copy password entry for $user'
 
343
    else
 
344
        echo $pwd >> $rootfs/etc/passwd
 
345
    fi
 
346
    shad=`getent shadow $user`
 
347
    echo $shad >> $rootfs/etc/shadow
 
348
}
 
349
 
 
350
clean()
 
351
{
 
352
    release=$1
 
353
    cache="/var/cache/lxc/$release"
 
354
 
 
355
    if [ ! -e $cache ]; then
 
356
        exit 0
 
357
    fi
 
358
 
 
359
    # lock, so we won't purge while someone is creating a repository
 
360
    (
 
361
        flock -n -x 200
 
362
        if [ $? != 0 ]; then
 
363
            echo "Cache repository is busy."
 
364
            exit 1
 
365
        fi
 
366
 
 
367
        echo -n "Purging the download cache..."
 
368
        rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
 
369
        exit 0
 
370
 
 
371
    ) 200>/var/lock/subsys/lxc
 
372
}
 
373
 
 
374
usage()
 
375
{
 
376
    cat <<EOF
 
377
$1 -h|--help -p|--path=<path> --clean [-a|--arch] [-b|--bindhome <user>] [--trim] [-r|--release]
 
378
release: lucid | maverick | natty | oneiric
 
379
trim: make a minimal (faster, but not upgrade-safe) container
 
380
bindhome: bind <user>'s home into the container
 
381
arch: amd64 or i386: defaults to host arch
 
382
EOF
 
383
    return 0
 
384
}
 
385
 
 
386
options=$(getopt -o a:b:hp:r:xn:c -l arch:,bindhome:,help,path:,release:,trim,name:,clean -- "$@")
 
387
if [ $? -ne 0 ]; then
 
388
    usage $(basename $0)
 
389
    exit 1
 
390
fi
 
391
eval set -- "$options"
 
392
 
 
393
release=lucid
 
394
if [ -f /etc/lsb-release ]; then
 
395
    . /etc/lsb-release
 
396
    case "$DISTRIB_CODENAME" in
 
397
        lucid|maverick|natty|oneiric)
 
398
            release=$DISTRIB_CODENAME
 
399
        ;;
 
400
    esac
 
401
fi
 
402
 
 
403
bindhome=
 
404
arch=$(arch)
 
405
 
 
406
# Code taken from debootstrap
 
407
if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
 
408
    arch=`/usr/bin/dpkg --print-architecture`
 
409
elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
 
410
    arch=`/usr/bin/udpkg --print-architecture`
 
411
else
 
412
    arch=$(arch)
 
413
    if [ "$arch" = "i686" ]; then
 
414
        arch="i386"
 
415
    elif [ "$arch" = "x86_64" ]; then
 
416
        arch="amd64"
 
417
    elif [ "$arch" = "armv7l" ]; then
 
418
        arch="armel"
 
419
    fi
 
420
fi
 
421
 
 
422
trim_container=0
 
423
hostarch=$arch
 
424
while true
 
425
do
 
426
    case "$1" in
 
427
    -h|--help)      usage $0 && exit 0;;
 
428
    -p|--path)      path=$2; shift 2;;
 
429
    -n|--name)      name=$2; shift 2;;
 
430
    -c|--clean)     clean=$2; shift 2;;
 
431
    -r|--release)   release=$2; shift 2;;
 
432
    -b|--bindhome)  bindhome=$2; shift 2;;
 
433
    -a|--arch)      arch=$2; shift 2;;
 
434
    -x|--trim)      trim_container=1; shift 1;;
 
435
    --)             shift 1; break ;;
 
436
        *)              break ;;
 
437
    esac
 
438
done
 
439
 
 
440
if [ "$arch" == "i686" ]; then
 
441
    arch=i386
 
442
fi
 
443
 
 
444
if [ ! -z "$clean" -a -z "$path" ]; then
 
445
    clean || exit 1
 
446
    exit 0
 
447
fi
 
448
 
 
449
if [ $hostarch = "i386" -a $arch = "amd64" ]; then
 
450
    echo "can't create amd64 container on i386"
 
451
    exit 1
 
452
fi
 
453
 
 
454
type debootstrap
 
455
if [ $? -ne 0 ]; then
 
456
    echo "'debootstrap' command is missing"
 
457
    exit 1
 
458
fi
 
459
 
 
460
if [ -z "$path" ]; then
 
461
    echo "'path' parameter is required"
 
462
    exit 1
 
463
fi
 
464
 
 
465
if [ "$(id -u)" != "0" ]; then
 
466
    echo "This script should be run as 'root'"
 
467
    exit 1
 
468
fi
 
469
 
 
470
rootfs=$path/rootfs
 
471
 
 
472
install_ubuntu $rootfs $release
 
473
if [ $? -ne 0 ]; then
 
474
    echo "failed to install ubuntu $release"
 
475
    exit 1
 
476
fi
 
477
 
 
478
configure_ubuntu $rootfs $name
 
479
if [ $? -ne 0 ]; then
 
480
    echo "failed to configure ubuntu $release for a container"
 
481
    exit 1
 
482
fi
 
483
 
 
484
copy_configuration $path $rootfs $name $arch
 
485
if [ $? -ne 0 ]; then
 
486
    echo "failed write configuration file"
 
487
    exit 1
 
488
fi
 
489
 
 
490
post_process $rootfs $release $trim_container
 
491
if [ ! -z $bindhome ]; then
 
492
        do_bindhome $rootfs $bindhome
 
493
fi
 
494
 
 
495
if [ ! -z $clean ]; then
 
496
    clean $release || exit 1
 
497
    exit 0
 
498
fi