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