]> git.proxmox.com Git - mirror_lxc.git/blame - templates/lxc-ubuntu.in
Make ubuntu templates squid-deb-proxy-client aware
[mirror_lxc.git] / templates / lxc-ubuntu.in
CommitLineData
3f033aa8
WM
1#!/bin/bash
2
3#
e2b4064f 4# template script for generating ubuntu container for LXC
3f033aa8 5#
e2b4064f 6# This script consolidates and extends the existing lxc ubuntu scripts
3f033aa8
WM
7#
8
8cd80b50
SG
9# Copyright © 2011 Serge Hallyn <serge.hallyn@canonical.com>
10# Copyright © 2010 Wilhelm Meier
3f033aa8
WM
11# Author: Wilhelm Meier <wilhelm.meier@fh-kl.de>
12#
acbb59f5
SH
13# This library is free software; you can redistribute it and/or
14# modify it under the terms of the GNU Lesser General Public
15# License as published by the Free Software Foundation; either
16# version 2.1 of the License, or (at your option) any later version.
17
18# This library is distributed in the hope that it will be useful,
19# but WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21# Lesser General Public License for more details.
22
23# You should have received a copy of the GNU Lesser General Public
24# License along with this library; if not, write to the Free Software
25# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
3f033aa8 26
1d61e5b9
SH
27set -e
28
f2a95ee1
SG
29LOCALSTATEDIR="@LOCALSTATEDIR@"
30LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@"
703d065d 31
e2b4064f
SH
32if [ -r /etc/default/lxc ]; then
33 . /etc/default/lxc
34fi
35
3f033aa8
WM
36configure_ubuntu()
37{
38 rootfs=$1
39 hostname=$2
f6144f0c 40 release=$3
2004e7da
GL
41 user=$4
42 password=$5
3f033aa8 43
a2abaa9e 44 # configure the network using the dhcp
3f033aa8 45 cat <<EOF > $rootfs/etc/network/interfaces
adca8543
SH
46# This file describes the network interfaces available on your system
47# and how to activate them. For more information, see interfaces(5).
48
49# The loopback network interface
3f033aa8
WM
50auto lo
51iface lo inet loopback
52
53auto eth0
54iface eth0 inet dhcp
55EOF
56
57 # set the hostname
58 cat <<EOF > $rootfs/etc/hostname
59$hostname
60EOF
61 # set minimal hosts
62 cat <<EOF > $rootfs/etc/hosts
adca8543
SH
63127.0.0.1 localhost
64127.0.1.1 $hostname
65
66# The following lines are desirable for IPv6 capable hosts
67::1 ip6-localhost ip6-loopback
68fe00::0 ip6-localnet
69ff00::0 ip6-mcastprefix
70ff02::1 ip6-allnodes
71ff02::2 ip6-allrouters
3f033aa8
WM
72EOF
73
adca8543 74 if [ ! -f $rootfs/etc/init/container-detect.conf ]; then
f6144f0c
SH
75 # suppress log level output for udev
76 sed -i "s/=\"err\"/=0/" $rootfs/etc/udev/udev.conf
3f033aa8 77
f6144f0c
SH
78 # remove jobs for consoles 5 and 6 since we only create 4 consoles in
79 # this template
80 rm -f $rootfs/etc/init/tty{5,6}.conf
81 fi
3f033aa8 82
ce5dbd82 83 if [ -z "$bindhome" ]; then
2004e7da
GL
84 chroot $rootfs useradd --create-home -s /bin/bash $user
85 echo "$user:$password" | chroot $rootfs chpasswd
ce5dbd82
SH
86 fi
87
18f823c1 88 # make sure we have the current locale defined in the container
dc7f6545 89 if [ -z "$LANG" ] || echo $LANG | grep -E -q "^C(\..+)*$"; then
18f823c1
SG
90 chroot $rootfs locale-gen en_US.UTF-8
91 chroot $rootfs update-locale LANG=en_US.UTF-8
92 else
dc7f6545
SG
93 chroot $rootfs locale-gen $LANG
94 chroot $rootfs update-locale LANG=$LANG
18f823c1
SG
95 fi
96
a2abaa9e 97 # generate new SSH keys
703d065d 98 if [ -x $rootfs$LOCALSTATEDIR/lib/dpkg/info/openssh-server.postinst ]; then
6cda3f5a
SG
99 cat > $rootfs/usr/sbin/policy-rc.d << EOF
100#!/bin/sh
101exit 101
102EOF
103 chmod +x $rootfs/usr/sbin/policy-rc.d
104
a2abaa9e
SG
105 rm -f $rootfs/etc/ssh/ssh_host_*key*
106 mv $rootfs/etc/init/ssh.conf $rootfs/etc/init/ssh.conf.disabled
703d065d 107 DPKG_MAINTSCRIPT_PACKAGE=openssh DPKG_MAINTSCRIPT_NAME=postinst chroot $rootfs $LOCALSTATEDIR/lib/dpkg/info/openssh-server.postinst configure
a2abaa9e 108 mv $rootfs/etc/init/ssh.conf.disabled $rootfs/etc/init/ssh.conf
6cda3f5a 109
c5d32181
SG
110 sed -i "s/root@$(hostname)/root@$hostname/g" $rootfs/etc/ssh/ssh_host_*.pub
111
6cda3f5a 112 rm -f $rootfs/usr/sbin/policy-rc.d
a2abaa9e
SG
113 fi
114
ce5dbd82
SH
115 return 0
116}
117
118# finish setting up the user in the container by injecting ssh key and
119# adding sudo group membership.
120# passed-in user is either 'ubuntu' or the user to bind in from host.
121finalize_user()
122{
123 user=$1
124
adca8543
SH
125 sudo_version=$(chroot $rootfs dpkg-query -W -f='${Version}' sudo)
126
127 if chroot $rootfs dpkg --compare-versions $sudo_version gt "1.8.3p1-1"; then
ce5dbd82
SH
128 groups="sudo"
129 else
130 groups="sudo admin"
131 fi
96bd45c8
SG
132
133 for group in $groups; do
134 chroot $rootfs groupadd --system $group >/dev/null 2>&1 || true
ce5dbd82 135 chroot $rootfs adduser ${user} $group >/dev/null 2>&1 || true
96bd45c8
SG
136 done
137
4759162d 138 if [ -n "$auth_key" -a -f "$auth_key" ]; then
1e1f8eeb
SG
139 u_path="/home/${user}/.ssh"
140 root_u_path="$rootfs/$u_path"
141 mkdir -p $root_u_path
142 cp $auth_key "$root_u_path/authorized_keys"
143 chroot $rootfs chown -R ${user}: "$u_path"
4759162d 144
1e1f8eeb 145 echo "Inserted SSH public key from $auth_key into /home/${user}/.ssh/authorized_keys"
4759162d 146 fi
3a3ba44a 147 return 0
3f033aa8
WM
148}
149
4213a747
CG
150# A function to try and autodetect squid-deb-proxy servers on the local network
151# if either the squid-deb-proxy-client package is installed on the host or
152# a parent container set the 50squid-deb-proxy-client file.
153squid_deb_proxy_autodetect()
154{
155 local apt_discover=/usr/share/squid-deb-proxy-client/apt-avahi-discover
156 local proxy_file=/etc/apt/apt.conf.d/50squid-deb-proxy-client
157 squid_proxy_line= # That's a global :/
158
159 # Maybe the host is aware of a squid-deb-proxy?
160 if [ -f $apt_discover ]; then
161 echo -n "Discovering squid-deb-proxy..."
162 squid_proxy_line=$($apt_discover)
163 if [ -n "$squid_proxy_line" ]; then
164 echo "found squid-deb-proxy: $squid_proxy_line"
165 else
166 echo "no squid-deb-proxy found"
167 fi
168 fi
169
170 # Are we in a nested container, and the parent already knows of a proxy?
171 if [ -f $proxy_file ]; then
172 # Extract the squid URL from the file (whatever is between "")
173 squid_proxy_line=`cat $proxy_file | sed "s/.*\"\(.*\)\".*/\1/"`
174 fi
175}
176
cf0f9033
SH
177#
178# Choose proxies for container
179# http_proxy will be used by debootstrap on the host.
180# APT_PROXY will be used to set /etc/apt/apt.conf.d/70proxy in the container.
181#
182choose_container_proxy()
183{
184 local rootfs=$1
185 local arch=$2
186
187 if [ -z "$HTTP_PROXY" ]; then
188 HTTP_PROXY="none"
189 fi
190 case "$HTTP_PROXY" in
191 none)
4213a747
CG
192 squid_deb_proxy_autodetect
193 if [ -n "$squid_proxy_line" ]; then
194 APT_PROXY=$squid_proxy_line
195 export http_proxy=$squid_proxy_line
196 else
197 APT_PROXY=
198 fi
cf0f9033
SH
199 ;;
200 apt)
201 RES=`apt-config shell APT_PROXY Acquire::http::Proxy`
202 eval $RES
203 [ -z "$APT_PROXY" ] || export http_proxy=$APT_PROXY
204 ;;
205 *)
206 APT_PROXY=$HTTP_PROXY
207 export http_proxy=$HTTP_PROXY
208 ;;
209 esac
210}
211
5a50e09a
SH
212write_sourceslist()
213{
214 # $1 => path to the rootfs
215 # $2 => architecture we want to add
216 # $3 => whether to use the multi-arch syntax or not
217
cf0f9033
SH
218 if [ -n "$APT_PROXY" ]; then
219 mkdir -p $rootfs/etc/apt/apt.conf.d
220 cat > $rootfs/etc/apt/apt.conf.d/70proxy << EOF
221Acquire::http::Proxy "$APT_PROXY" ;
222EOF
223 fi
224
5a50e09a
SH
225 case $2 in
226 amd64|i386)
227 MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu}
228 SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.ubuntu.com/ubuntu}
229 ;;
5a50e09a
SH
230 *)
231 MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
232 SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
233 ;;
234 esac
235 if [ -n "$3" ]; then
236 cat >> "$1/etc/apt/sources.list" << EOF
237deb [arch=$2] $MIRROR ${release} main restricted universe multiverse
238deb [arch=$2] $MIRROR ${release}-updates main restricted universe multiverse
239deb [arch=$2] $SECURITY_MIRROR ${release}-security main restricted universe multiverse
240EOF
241 else
242 cat >> "$1/etc/apt/sources.list" << EOF
243deb $MIRROR ${release} main restricted universe multiverse
244deb $MIRROR ${release}-updates main restricted universe multiverse
245deb $SECURITY_MIRROR ${release}-security main restricted universe multiverse
246EOF
247 fi
248}
249
28b62856
GL
250install_packages()
251{
252 local rootfs="$1"
253 shift
254 local packages="$*"
255 if [ -z $update ]
256 then
257 chroot $rootfs apt-get update
258 update=true
259 fi
260 if [ -n "${packages}" ]
261 then
262 chroot $rootfs apt-get install --force-yes -y --no-install-recommends ${packages}
263 fi
264}
265
f1ccde27
SH
266cleanup()
267{
268 rm -rf $cache/partial-$arch
269 rm -rf $cache/rootfs-$arch
270}
271
91a5df88
SH
272suggest_flush()
273{
274 echo "Container upgrade failed. The container cache may be out of date,"
3f5f5d99 275 echo "in which case flushing the cache (see -F in the help output) may help."
91a5df88
SH
276}
277
3f033aa8
WM
278download_ubuntu()
279{
3f033aa8
WM
280 cache=$1
281 arch=$2
e2b4064f 282 release=$3
28b62856 283
e8eab8b6 284 packages_template=${packages_template:-"ssh,vim"}
fade719e
SG
285
286 # Try to guess a list of langpacks to install
287 langpacks="language-pack-en"
288
289 if which dpkg >/dev/null 2>&1; then
89573feb 290 langpacks=`(echo $langpacks &&
fade719e
SG
291 dpkg -l | grep -E "^ii language-pack-[a-z]* " |
292 cut -d ' ' -f3) | sort -u`
293 fi
28b62856 294 packages_template="${packages_template},$(echo $langpacks | sed 's/ /,/g')"
fade719e
SG
295
296
28b62856 297 echo "Installing packages in template: ${packages_template}"
3f033aa8 298
f1ccde27 299 trap cleanup EXIT SIGHUP SIGINT SIGTERM
3f033aa8
WM
300 # check the mini ubuntu was not already downloaded
301 mkdir -p "$cache/partial-$arch"
302 if [ $? -ne 0 ]; then
e2b4064f
SH
303 echo "Failed to create '$cache/partial-$arch' directory"
304 return 1
3f033aa8
WM
305 fi
306
cf0f9033 307 choose_container_proxy $cache/partial-$arch/ $arch
3f033aa8 308 # download a mini ubuntu into a cache
e2b4064f 309 echo "Downloading ubuntu $release minimal ..."
5a50e09a 310 if [ -n "$(which qemu-debootstrap)" ]; then
28b62856 311 qemu-debootstrap --verbose --components=main,universe --arch=$arch --include=${packages_template} $release $cache/partial-$arch $MIRROR
5a50e09a 312 else
28b62856 313 debootstrap --verbose --components=main,universe --arch=$arch --include=${packages_template} $release $cache/partial-$arch $MIRROR
5a50e09a
SH
314 fi
315
3f033aa8 316 if [ $? -ne 0 ]; then
e2b4064f
SH
317 echo "Failed to download the rootfs, aborting."
318 return 1
3f033aa8
WM
319 fi
320
2e44ed1e
SH
321 # Serge isn't sure whether we should avoid doing this when
322 # $release == `distro-info -d`
323 echo "Installing updates"
5a50e09a
SH
324 > $cache/partial-$arch/etc/apt/sources.list
325 write_sourceslist $cache/partial-$arch/ $arch
326
2e44ed1e
SH
327 chroot "$1/partial-${arch}" apt-get update
328 if [ $? -ne 0 ]; then
329 echo "Failed to update the apt cache"
330 return 1
331 fi
332 cat > "$1/partial-${arch}"/usr/sbin/policy-rc.d << EOF
333#!/bin/sh
334exit 101
335EOF
336 chmod +x "$1/partial-${arch}"/usr/sbin/policy-rc.d
337
91a5df88 338 lxc-unshare -s MOUNT -- chroot "$1/partial-${arch}" apt-get dist-upgrade -y || { suggest_flush; false; }
2e44ed1e
SH
339 rm -f "$1/partial-${arch}"/usr/sbin/policy-rc.d
340
06f5c632
SH
341 chroot "$1/partial-${arch}" apt-get clean
342
15da01b3 343 mv "$1/partial-$arch" "$1/rootfs-$arch"
f1ccde27
SH
344 trap EXIT
345 trap SIGINT
346 trap SIGTERM
347 trap SIGHUP
15da01b3 348 echo "Download complete"
3f033aa8
WM
349 return 0
350}
351
352copy_ubuntu()
353{
354 cache=$1
355 arch=$2
356 rootfs=$3
357
358 # make a local copy of the miniubuntu
f6144f0c 359 echo "Copying rootfs to $rootfs ..."
6d8ac56b 360 mkdir -p $rootfs
44d39789 361 rsync -Ha $cache/rootfs-$arch/ $rootfs/ || return 1
3f033aa8
WM
362 return 0
363}
364
365install_ubuntu()
366{
3f033aa8 367 rootfs=$1
e2b4064f 368 release=$2
bb59e078 369 flushcache=$3
703d065d
GL
370 cache="$LOCALSTATEDIR/cache/lxc/$release"
371 mkdir -p $LOCALSTATEDIR/lock/subsys/
adca8543 372
3f033aa8 373 (
17abf278 374 flock -x 9
adca8543
SH
375 if [ $? -ne 0 ]; then
376 echo "Cache repository is busy."
377 return 1
378 fi
3f033aa8 379
3f033aa8 380
adca8543
SH
381 if [ $flushcache -eq 1 ]; then
382 echo "Flushing cache..."
383 rm -rf "$cache/partial-$arch"
384 rm -rf "$cache/rootfs-$arch"
385 fi
bb59e078 386
adca8543
SH
387 echo "Checking cache download in $cache/rootfs-$arch ... "
388 if [ ! -e "$cache/rootfs-$arch" ]; then
28b62856 389 download_ubuntu $cache $arch $release
adca8543
SH
390 if [ $? -ne 0 ]; then
391 echo "Failed to download 'ubuntu $release base'"
392 return 1
393 fi
394 fi
3f033aa8 395
adca8543
SH
396 echo "Copy $cache/rootfs-$arch to $rootfs ... "
397 copy_ubuntu $cache $arch $rootfs
398 if [ $? -ne 0 ]; then
399 echo "Failed to copy rootfs"
400 return 1
401 fi
3f033aa8 402
adca8543 403 return 0
3f033aa8 404
17abf278 405 ) 9>$LOCALSTATEDIR/lock/subsys/lxc-ubuntu$release
3f033aa8
WM
406
407 return $?
408}
409
410copy_configuration()
411{
412 path=$1
413 rootfs=$2
414 name=$3
e2b4064f 415 arch=$4
f6144f0c 416 release=$5
e2b4064f
SH
417
418 if [ $arch = "i386" ]; then
419 arch="i686"
420 fi
3f033aa8 421
4759162d
SH
422 # if there is exactly one veth network entry, make sure it has an
423 # associated hwaddr.
424 nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l`
425 if [ $nics -eq 1 ]; then
daaf41b3 426 grep -q "^lxc.network.hwaddr" $path/config || sed -i -e "/^lxc\.network\.type[ \t]*=[ \t]*veth/a lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')" $path/config
4759162d
SH
427 fi
428
f2a95ee1
SG
429 # Generate the configuration file
430 ## Create the fstab (empty by default)
431 touch $path/fstab
432
433 ## Relocate all the network config entries
434 sed -i -e "/lxc.network/{w ${path}/config-network" -e "d}" $path/config
435
436 ## Relocate any other config entries
437 sed -i -e "/lxc./{w ${path}/config-auto" -e "d}" $path/config
438
439 ## Add all the includes
440 echo "" >> $path/config
441 echo "# Common configuration" >> $path/config
442 if [ -e "${LXC_TEMPLATE_CONFIG}/ubuntu.common.conf" ]; then
443 echo "lxc.include = ${LXC_TEMPLATE_CONFIG}/ubuntu.common.conf" >> $path/config
444 fi
445 if [ -e "${LXC_TEMPLATE_CONFIG}/ubuntu.${release}.conf" ]; then
446 echo "lxc.include = ${LXC_TEMPLATE_CONFIG}/ubuntu.${release}.conf" >> $path/config
447 fi
448
449 ## Add the container-specific config
450 echo "" >> $path/config
451 echo "# Container specific configuration" >> $path/config
452 [ -e "$path/config-auto" ] && cat $path/config-auto >> $path/config && rm $path/config-auto
1881820a 453 grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config
3a3ba44a 454 cat <<EOF >> $path/config
daaf41b3 455lxc.mount = $path/fstab
daaf41b3 456lxc.utsname = $name
e2b4064f 457lxc.arch = $arch
3f033aa8
WM
458EOF
459
f2a95ee1
SG
460 ## Re-add the previously removed network config
461 echo "" >> $path/config
462 echo "# Network configuration" >> $path/config
463 cat $path/config-network >> $path/config
464 rm $path/config-network
3f033aa8
WM
465
466 if [ $? -ne 0 ]; then
adca8543
SH
467 echo "Failed to add configuration"
468 return 1
3f033aa8
WM
469 fi
470
471 return 0
472}
473
e2b4064f
SH
474post_process()
475{
476 rootfs=$1
477 release=$2
28b62856 478 packages=$3
e2b4064f 479
7ed86e44
SG
480 # Disable service startup
481 cat > $rootfs/usr/sbin/policy-rc.d << EOF
482#!/bin/sh
483exit 101
484EOF
485 chmod +x $rootfs/usr/sbin/policy-rc.d
486
2ef89d56 487 if [ ! -f $rootfs/etc/init/container-detect.conf ]; then
adca8543
SH
488 # Make sure we have a working resolv.conf
489 cresolvonf="${rootfs}/etc/resolv.conf"
490 mv $cresolvonf ${cresolvonf}.lxcbak
491 cat /etc/resolv.conf > ${cresolvonf}
492
f34ff296 493 # for lucid, if not trimming, then add the ubuntu-virt
e2b4064f 494 # ppa and install lxcguest
f34ff296 495 if [ $release = "lucid" ]; then
91a5df88 496 chroot $rootfs apt-get update
28b62856 497 install_packages $rootfs "python-software-properties"
e2b4064f 498 chroot $rootfs add-apt-repository ppa:ubuntu-virt/ppa
e2b4064f 499 fi
adca8543 500
2e44ed1e 501 chroot $rootfs apt-get update
e2b4064f 502 chroot $rootfs apt-get install --force-yes -y lxcguest
adca8543
SH
503
504 # Restore old resolv.conf
505 rm -f ${cresolvonf}
506 mv ${cresolvonf}.lxcbak ${cresolvonf}
e2b4064f 507 fi
5a50e09a
SH
508
509 # If the container isn't running a native architecture, setup multiarch
510 if [ -x "$(ls -1 ${rootfs}/usr/bin/qemu-*-static 2>/dev/null)" ]; then
40f6ee00
SH
511 dpkg_version=$(chroot $rootfs dpkg-query -W -f='${Version}' dpkg)
512 if chroot $rootfs dpkg --compare-versions $dpkg_version ge "1.16.2"; then
513 chroot $rootfs dpkg --add-architecture ${hostarch}
514 else
515 mkdir -p ${rootfs}/etc/dpkg/dpkg.cfg.d
516 echo "foreign-architecture ${hostarch}" > ${rootfs}/etc/dpkg/dpkg.cfg.d/lxc-multiarch
517 fi
5a50e09a
SH
518
519 # Save existing value of MIRROR and SECURITY_MIRROR
520 DEFAULT_MIRROR=$MIRROR
521 DEFAULT_SECURITY_MIRROR=$SECURITY_MIRROR
522
523 # Write a new sources.list containing both native and multiarch entries
524 > ${rootfs}/etc/apt/sources.list
525 write_sourceslist $rootfs $arch "native"
526
527 MIRROR=$DEFAULT_MIRROR
528 SECURITY_MIRROR=$DEFAULT_SECURITY_MIRROR
529 write_sourceslist $rootfs $hostarch "multiarch"
530
531 # Finally update the lists and install upstart using the host architecture
d08c3aae 532 HOST_PACKAGES="upstart:${hostarch} mountall:${hostarch} isc-dhcp-client:${hostarch}"
5a50e09a 533 chroot $rootfs apt-get update
d08c3aae
SG
534 if chroot $rootfs dpkg -l iproute2 | grep -q ^ii; then
535 HOST_PACKAGES="$HOST_PACKAGES iproute2:${hostarch}"
536 else
537 HOST_PACKAGES="$HOST_PACKAGES iproute:${hostarch}"
538 fi
28b62856
GL
539 install_packages $rootfs $HOST_PACKAGES
540 fi
541
542 # Install Packages in container
d2305c4c 543 if [ -n "$packages" ]
28b62856
GL
544 then
545 local packages="`echo $packages | sed 's/,/ /g'`"
546 echo "Installing packages: ${packages}"
547 install_packages $rootfs $packages
5a50e09a 548 fi
42ff5f0f 549
0a3673e8
SG
550 # Set initial timezone as on host
551 if [ -f /etc/timezone ]; then
552 cat /etc/timezone > $rootfs/etc/timezone
553 chroot $rootfs dpkg-reconfigure -f noninteractive tzdata
554 elif [ -f /etc/sysconfig/clock ]; then
17abf278 555 . /etc/sysconfig/clock
0a3673e8
SG
556 echo $ZONE > $rootfs/etc/timezone
557 chroot $rootfs dpkg-reconfigure -f noninteractive tzdata
558 else
559 echo "Timezone in container is not configured. Adjust it manually."
560 fi
561
adca8543 562 # rmdir /dev/shm for containers that have /run/shm
42ff5f0f
SH
563 # I'm afraid of doing rm -rf $rootfs/dev/shm, in case it did
564 # get bind mounted to the host's /run/shm. So try to rmdir
565 # it, and in case that fails move it out of the way.
5ff33774 566 # NOTE: This can only be removed once 12.04 goes out of support
542939c3 567 if [ ! -L $rootfs/dev/shm ] && [ -d $rootfs/run/shm ] && [ -e $rootfs/dev/shm ]; then
5ff33774 568 rmdir $rootfs/dev/shm 2>/dev/null || mv $rootfs/dev/shm $rootfs/dev/shm.bak
42ff5f0f
SH
569 ln -s /run/shm $rootfs/dev/shm
570 fi
7ed86e44
SG
571
572 # Re-enable service startup
573 rm $rootfs/usr/sbin/policy-rc.d
e2b4064f
SH
574}
575
576do_bindhome()
577{
578 rootfs=$1
579 user=$2
580
e2b4064f 581 # copy /etc/passwd, /etc/shadow, and /etc/group entries into container
39aa5856
SH
582 pwd=`getent passwd $user` || { echo "Failed to copy password entry for $user"; false; }
583 echo $pwd >> $rootfs/etc/passwd
584
585 # make sure user's shell exists in the container
586 shell=`echo $pwd | cut -d: -f 7`
587 if [ ! -x $rootfs/$shell ]; then
588 echo "shell $shell for user $user was not found in the container."
589 pkg=`dpkg -S $(readlink -m $shell) | cut -d ':' -f1`
590 echo "Installing $pkg"
28b62856 591 install_packages $rootfs $pkg
e2b4064f 592 fi
39aa5856 593
e2b4064f 594 shad=`getent shadow $user`
39aa5856 595 echo "$shad" >> $rootfs/etc/shadow
8565ea1c
SH
596
597 # bind-mount the user's path into the container's /home
598 h=`getent passwd $user | cut -d: -f 6`
599 mkdir -p $rootfs/$h
adca8543
SH
600
601 # use relative path in container
602 h2=${h#/}
603 while [ ${h2:0:1} = "/" ]; do
604 h2=${h2#/}
605 done
e4208a19 606 echo "$h $h2 none bind 0 0" >> $path/fstab
39aa5856
SH
607
608 # Make sure the group exists in container
9db1aba4
SH
609 grp=`echo $pwd | cut -d: -f 4` # group number for $user
610 grpe=`getent group $grp` || return 0 # if host doesn't define grp, ignore in container
611 chroot $rootfs getent group "$grpe" || echo "$grpe" >> $rootfs/etc/group
e2b4064f
SH
612}
613
3f033aa8
WM
614usage()
615{
616 cat <<EOF
2ef89d56 617$1 -h|--help [-a|--arch] [-b|--bindhome <user>] [-d|--debug]
52c8f624 618 [-F | --flush-cache] [-r|--release <release>] [ -S | --auth-key <keyfile>]
2004e7da 619 [--rootfs <rootfs>] [--packages <packages>] [-u|--user <user>] [--password <password>]
adca8543 620release: the ubuntu release (e.g. precise): defaults to host release on ubuntu, otherwise uses latest LTS
e2b4064f 621bindhome: bind <user>'s home into the container
ce5dbd82 622 The ubuntu user will not be created, and <user> will have
adca8543
SH
623 sudo access.
624arch: the container architecture (e.g. amd64): defaults to host arch
52c8f624 625auth-key: SSH Public key file to inject into container
2004e7da 626packages: list of packages to add comma separated
3f033aa8
WM
627EOF
628 return 0
629}
630
5eb28ae4 631options=$(getopt -o a:b:hp:r:n:FS:du: -l arch:,bindhome:,help,path:,release:,name:,flush-cache,auth-key:,debug,rootfs:,packages:,user:,password:,mirror:,security-mirror: -- "$@")
3f033aa8 632if [ $? -ne 0 ]; then
bc24fe4d
WM
633 usage $(basename $0)
634 exit 1
3f033aa8
WM
635fi
636eval set -- "$options"
637
adca8543 638release=precise # Default to the last Ubuntu LTS release for non-Ubuntu systems
c6992ecf
SH
639if [ -f /etc/lsb-release ]; then
640 . /etc/lsb-release
adca8543
SH
641 if [ "$DISTRIB_ID" = "Ubuntu" ]; then
642 release=$DISTRIB_CODENAME
643 fi
c6992ecf
SH
644fi
645
e2b4064f 646bindhome=
e2b4064f 647
8339b4c8
SH
648# Code taken from debootstrap
649if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
650 arch=`/usr/bin/dpkg --print-architecture`
169bf5e0 651elif which udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
8339b4c8
SH
652 arch=`/usr/bin/udpkg --print-architecture`
653else
ed4616b1 654 arch=$(uname -m)
8339b4c8
SH
655 if [ "$arch" = "i686" ]; then
656 arch="i386"
657 elif [ "$arch" = "x86_64" ]; then
658 arch="amd64"
659 elif [ "$arch" = "armv7l" ]; then
8a63c0a9 660 arch="armhf"
8339b4c8 661 fi
e2b4064f
SH
662fi
663
52c8f624 664debug=0
e2b4064f 665hostarch=$arch
bb59e078 666flushcache=0
d2305c4c 667packages=""
2004e7da
GL
668user="ubuntu"
669password="ubuntu"
3f033aa8
WM
670while true
671do
672 case "$1" in
e2b4064f 673 -h|--help) usage $0 && exit 0;;
1897e3bc 674 --rootfs) rootfs=$2; shift 2;;
e2b4064f
SH
675 -p|--path) path=$2; shift 2;;
676 -n|--name) name=$2; shift 2;;
2004e7da
GL
677 -u|--user) user=$2; shift 2;;
678 --password) password=$2; shift 2;;
bb59e078 679 -F|--flush-cache) flushcache=1; shift 1;;
e2b4064f 680 -r|--release) release=$2; shift 2;;
2004e7da 681 --packages) packages=$2; shift 2;;
e2b4064f
SH
682 -b|--bindhome) bindhome=$2; shift 2;;
683 -a|--arch) arch=$2; shift 2;;
52c8f624
SH
684 -S|--auth-key) auth_key=$2; shift 2;;
685 -d|--debug) debug=1; shift 1;;
5eb28ae4
GL
686 --mirror) MIRROR=$2; shift 2;;
687 --security-mirror) SECURITY_MIRROR=$2; shift 2;;
e2b4064f 688 --) shift 1; break ;;
bc24fe4d 689 *) break ;;
3f033aa8
WM
690 esac
691done
692
52c8f624
SH
693if [ $debug -eq 1 ]; then
694 set -x
695fi
696
9db1aba4
SH
697if [ -n "$bindhome" ]; then
698 pwd=`getent passwd $bindhome`
699 if [ $? -ne 0 ]; then
700 echo "Error: no password entry found for $bindhome"
701 exit 1
702 fi
8565ea1c
SH
703fi
704
705
17abf278 706if [ "$arch" = "i686" ]; then
e2b4064f
SH
707 arch=i386
708fi
709
e2b4064f 710if [ $hostarch = "i386" -a $arch = "amd64" ]; then
8a63c0a9
SG
711 echo "can't create $arch container on $hostarch"
712 exit 1
713fi
714
715if [ $hostarch = "armhf" -o $hostarch = "armel" ] && \
716 [ $arch != "armhf" -a $arch != "armel" ]; then
717 echo "can't create $arch container on $hostarch"
718 exit 1
719fi
720
721if [ $hostarch = "powerpc" -a $arch != "powerpc" ]; then
722 echo "can't create $arch container on $hostarch"
e2b4064f
SH
723 exit 1
724fi
725
169bf5e0 726which debootstrap >/dev/null 2>&1 || { echo "'debootstrap' command is missing" >&2; false; }
3f033aa8
WM
727
728if [ -z "$path" ]; then
729 echo "'path' parameter is required"
730 exit 1
731fi
732
733if [ "$(id -u)" != "0" ]; then
734 echo "This script should be run as 'root'"
735 exit 1
736fi
737
1881820a
SH
738# detect rootfs
739config="$path/config"
1897e3bc
SH
740# if $rootfs exists here, it was passed in with --rootfs
741if [ -z "$rootfs" ]; then
742 if grep -q '^lxc.rootfs' $config 2>/dev/null ; then
853d58fd 743 rootfs=$(awk -F= '/^lxc.rootfs =/{ print $2 }' $config)
1897e3bc
SH
744 else
745 rootfs=$path/rootfs
746 fi
1881820a 747fi
3f033aa8 748
28b62856 749install_ubuntu $rootfs $release $flushcache
3f033aa8 750if [ $? -ne 0 ]; then
e2b4064f 751 echo "failed to install ubuntu $release"
3f033aa8
WM
752 exit 1
753fi
754
2004e7da 755configure_ubuntu $rootfs $name $release $user $password
3f033aa8 756if [ $? -ne 0 ]; then
e2b4064f 757 echo "failed to configure ubuntu $release for a container"
3f033aa8
WM
758 exit 1
759fi
760
f6144f0c 761copy_configuration $path $rootfs $name $arch $release
3f033aa8
WM
762if [ $? -ne 0 ]; then
763 echo "failed write configuration file"
764 exit 1
765fi
766
28b62856 767post_process $rootfs $release $trim_container $packages
ce5dbd82
SH
768
769if [ -n "$bindhome" ]; then
770 do_bindhome $rootfs $bindhome
771 finalize_user $bindhome
772else
2004e7da 773 finalize_user $user
e2b4064f
SH
774fi
775
f6144f0c
SH
776echo ""
777echo "##"
c6ed4d04 778if [ -n "$bindhome" ]; then
1e1f8eeb 779 echo "# Log in as user $bindhome"
c6ed4d04 780else
2004e7da 781 echo "# The default user is '$user' with password '$password'!"
1e1f8eeb 782 echo "# Use the 'sudo' command to run tasks as root in the container."
c6ed4d04 783fi
f6144f0c
SH
784echo "##"
785echo ""