]>
Commit | Line | Data |
---|---|---|
bad69158 | 1 | #!/bin/bash |
7afc269d | 2 | |
fb7460fe DL |
3 | # |
4 | # lxc: linux Container library | |
06388011 | 5 | |
fb7460fe DL |
6 | # Authors: |
7 | # Daniel Lezcano <daniel.lezcano@free.fr> | |
8 | ||
9 | # This library is free software; you can redistribute it and/or | |
10 | # modify it under the terms of the GNU Lesser General Public | |
11 | # License as published by the Free Software Foundation; either | |
12 | # version 2.1 of the License, or (at your option) any later version. | |
13 | ||
14 | # This library is distributed in the hope that it will be useful, | |
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14d9c0f0 | 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
fb7460fe | 17 | # Lesser General Public License for more details. |
06388011 | 18 | |
fb7460fe DL |
19 | # You should have received a copy of the GNU Lesser General Public |
20 | # License along with this library; if not, write to the Free Software | |
250b1eec | 21 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
06388011 | 22 | |
8ec981fc | 23 | # Detect use under userns (unsupported) |
c63c04fc | 24 | for arg in "$@"; do |
96283b54 SG |
25 | [ "$arg" = "--" ] && break |
26 | if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then | |
8ec981fc SG |
27 | echo "This template can't be used for unprivileged containers." 1>&2 |
28 | echo "You may want to try the \"download\" template instead." 1>&2 | |
29 | exit 1 | |
30 | fi | |
31 | done | |
32 | ||
207bf0e4 SG |
33 | # Make sure the usual locations are in PATH |
34 | export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin | |
192dbe6f | 35 | export GREP_OPTIONS="" |
207bf0e4 | 36 | |
d312bb74 | 37 | MIRROR=${MIRROR:-http://deb.debian.org/debian} |
5d20559c | 38 | SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.debian.org/} |
00fe5e1d SG |
39 | LOCALSTATEDIR="@LOCALSTATEDIR@" |
40 | LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@" | |
6dc6f80b KC |
41 | # Allows the lxc-cache directory to be set by environment variable |
42 | LXC_CACHE_PATH=${LXC_CACHE_PATH:-"$LOCALSTATEDIR/cache/lxc"} | |
2a7c16dc | 43 | |
d50cebd6 LV |
44 | find_interpreter() |
45 | { | |
46 | given_interpreter=$(basename "$1") | |
47 | ||
48 | if [ ! -d /proc/sys/fs/binfmt_misc/ ] ; then | |
49 | return 1 | |
50 | fi | |
51 | for file in /proc/sys/fs/binfmt_misc/* ; do | |
52 | if [ "$file" = "/proc/sys/fs/binfmt_misc/register" -o \ | |
53 | "$file" = "/proc/sys/fs/binfmt_misc/status" ] ; then | |
54 | continue | |
55 | fi | |
56 | interpreter_path=$(sed -n "/^interpreter/s/interpreter \([^[:space:]]*\)/\1/p" "$file") | |
bf39edb3 | 57 | interpreter=$(basename "$interpreter_path") |
d50cebd6 LV |
58 | |
59 | if [ "$given_interpreter" = "$interpreter" ] ; then | |
60 | echo "$interpreter_path" | |
61 | return 0 | |
62 | fi | |
63 | done | |
64 | return 1 | |
65 | } | |
66 | ||
fb7460fe DL |
67 | configure_debian() |
68 | { | |
69 | rootfs=$1 | |
70 | hostname=$2 | |
a3d42f4b | 71 | num_tty=$3 |
fb7460fe | 72 | |
4e0eb765 DB |
73 | # squeeze only has /dev/tty and /dev/tty0 by default, |
74 | # therefore creating missing device nodes for tty1-4. | |
bf39edb3 AF |
75 | for tty in $(seq 1 "$num_tty"); do |
76 | if [ ! -e "$rootfs/dev/tty$tty" ]; then | |
77 | mknod "$rootfs/dev/tty$tty" c 4 "$tty" | |
14d9c0f0 | 78 | fi |
4e0eb765 DB |
79 | done |
80 | ||
fb7460fe DL |
81 | # configure the inittab |
82 | cat <<EOF > $rootfs/etc/inittab | |
06388011 | 83 | id:3:initdefault: |
84 | si::sysinit:/etc/init.d/rcS | |
85 | l0:0:wait:/etc/init.d/rc 0 | |
86 | l1:1:wait:/etc/init.d/rc 1 | |
87 | l2:2:wait:/etc/init.d/rc 2 | |
88 | l3:3:wait:/etc/init.d/rc 3 | |
89 | l4:4:wait:/etc/init.d/rc 4 | |
90 | l5:5:wait:/etc/init.d/rc 5 | |
91 | l6:6:wait:/etc/init.d/rc 6 | |
92 | # Normally not reached, but fallthrough in case of emergency. | |
93 | z6:6:respawn:/sbin/sulogin | |
94 | 1:2345:respawn:/sbin/getty 38400 console | |
bf39edb3 | 95 | $(for tty in $(seq 1 "$num_tty"); do echo "c${tty}:12345:respawn:/sbin/getty 38400 tty${tty} linux" ; done;) |
f79d43bb | 96 | p6::ctrlaltdel:/sbin/init 6 |
6bf8daf9 | 97 | p0::powerfail:/sbin/init 0 |
06388011 | 98 | EOF |
06388011 | 99 | |
23e88083 | 100 | # symlink mtab |
bf39edb3 AF |
101 | [ -e "$rootfs/etc/mtab" ] && rm "$rootfs/etc/mtab" |
102 | ln -s /proc/self/mounts "$rootfs/etc/mtab" | |
23e88083 | 103 | |
fb7460fe | 104 | # disable selinux in debian |
bf39edb3 AF |
105 | mkdir -p "$rootfs/selinux" |
106 | echo 0 > "$rootfs/selinux/enforce" | |
06388011 | 107 | |
fb7460fe DL |
108 | # configure the network using the dhcp |
109 | cat <<EOF > $rootfs/etc/network/interfaces | |
110 | auto lo | |
111 | iface lo inet loopback | |
06388011 | 112 | |
fb7460fe DL |
113 | auto eth0 |
114 | iface eth0 inet dhcp | |
06388011 | 115 | EOF |
1846e71a | 116 | |
fb7460fe DL |
117 | # set the hostname |
118 | cat <<EOF > $rootfs/etc/hostname | |
119 | $hostname | |
120 | EOF | |
06388011 | 121 | |
fb7460fe | 122 | # reconfigure some services |
06388011 | 123 | |
e160e450 | 124 | # but first reconfigure locales - so we get no noisy perl-warnings |
c99055ea | 125 | if [ -z "$LANG" ] || echo $LANG | grep -E -q "^C(\..+)*$"; then |
bf39edb3 | 126 | cat >> "$rootfs/etc/locale.gen" << EOF |
e160e450 AF |
127 | en_US.UTF-8 UTF-8 |
128 | EOF | |
bf39edb3 AF |
129 | chroot "$rootfs" locale-gen en_US.UTF-8 UTF-8 |
130 | chroot "$rootfs" update-locale LANG=en_US.UTF-8 | |
e160e450 | 131 | else |
bf39edb3 AF |
132 | encoding=$(echo "$LANG" | cut -d. -f2) |
133 | chroot "$rootfs" sed -e "s/^# \(${LANG} ${encoding}\)/\1/" \ | |
e160e450 | 134 | -i /etc/locale.gen 2> /dev/null |
bf39edb3 | 135 | cat >> "$rootfs/etc/locale.gen" << EOF |
e160e450 AF |
136 | $LANG $encoding |
137 | EOF | |
bf39edb3 AF |
138 | chroot "$rootfs" locale-gen "$LANG" "$encoding" |
139 | chroot "$rootfs" update-locale LANG="$LANG" | |
e160e450 AF |
140 | fi |
141 | ||
fb7460fe | 142 | # remove pointless services in a container |
bf39edb3 AF |
143 | chroot "$rootfs" /usr/sbin/update-rc.d -f checkroot.sh disable |
144 | chroot "$rootfs" /usr/sbin/update-rc.d -f umountfs disable | |
145 | chroot "$rootfs" /usr/sbin/update-rc.d -f hwclock.sh disable | |
146 | chroot "$rootfs" /usr/sbin/update-rc.d -f hwclockfirst.sh disable | |
19d618b1 | 147 | |
ce68d5b4 | 148 | # generate new SSH keys |
bf39edb3 AF |
149 | if [ -x "$rootfs/var/lib/dpkg/info/openssh-server.postinst" ]; then |
150 | cat > "$rootfs/usr/sbin/policy-rc.d" << EOF | |
ce68d5b4 SG |
151 | #!/bin/sh |
152 | exit 101 | |
153 | EOF | |
bf39edb3 | 154 | chmod +x "$rootfs/usr/sbin/policy-rc.d" |
ce68d5b4 | 155 | |
bf39edb3 AF |
156 | if [ -f "$rootfs/etc/init/ssh.conf" ]; then |
157 | mv "$rootfs/etc/init/ssh.conf" "$rootfs/etc/init/ssh.conf.disabled" | |
ce68d5b4 SG |
158 | fi |
159 | ||
bf39edb3 | 160 | rm -f "$rootfs/etc/ssh/"ssh_host_*key* |
ce68d5b4 | 161 | |
bf39edb3 AF |
162 | DPKG_MAINTSCRIPT_PACKAGE=openssh DPKG_MAINTSCRIPT_NAME=postinst chroot "$rootfs" /var/lib/dpkg/info/openssh-server.postinst configure |
163 | sed -i "s/root@$(hostname)/root@$hostname/g" "$rootfs/etc/ssh/"ssh_host_*.pub | |
ce68d5b4 SG |
164 | |
165 | if [ -f "$rootfs/etc/init/ssh.conf.disabled" ]; then | |
bf39edb3 | 166 | mv "$rootfs/etc/init/ssh.conf.disabled" "$rootfs/etc/init/ssh.conf" |
ce68d5b4 SG |
167 | fi |
168 | ||
bf39edb3 | 169 | rm -f "$rootfs/usr/sbin/policy-rc.d" |
ce68d5b4 SG |
170 | fi |
171 | ||
f7365a24 | 172 | # set initial timezone as on host |
173 | if [ -f /etc/timezone ]; then | |
bf39edb3 AF |
174 | cat /etc/timezone > "$rootfs/etc/timezone" |
175 | chroot "$rootfs" dpkg-reconfigure -f noninteractive tzdata | |
f7365a24 | 176 | elif [ -f /etc/sysconfig/clock ]; then |
17abf278 | 177 | . /etc/sysconfig/clock |
bf39edb3 AF |
178 | echo "$ZONE" > "$rootfs/etc/timezone" |
179 | chroot "$rootfs" dpkg-reconfigure -f noninteractive tzdata | |
f7365a24 | 180 | else |
181 | echo "Timezone in container is not configured. Adjust it manually." | |
182 | fi | |
183 | ||
9b6fb5d4 BJ |
184 | if [ -n "$authkey" ]; then |
185 | local ssh_dir_path="${rootfs}/root/.ssh" | |
186 | mkdir -p "$ssh_dir_path" | |
187 | cp "$authkey" "${ssh_dir_path}/authorized_keys" | |
188 | chmod 700 "$ssh_dir_path" | |
189 | echo "Inserted SSH public key from '$authkey' into /root/.ssh/authorized_keys" | |
190 | fi | |
191 | ||
19d618b1 | 192 | return 0 |
06388011 | 193 | } |
194 | ||
177f2cd2 AD |
195 | write_sourceslist() |
196 | { | |
197 | local rootfs="$1"; shift | |
198 | local release="$1"; shift | |
199 | local arch="$1"; shift | |
200 | ||
201 | local prefix="deb" | |
202 | if [ -n "${arch}" ]; then | |
203 | prefix="deb [arch=${arch}]" | |
204 | fi | |
205 | ||
c2a85d04 AT |
206 | if [ "$mainonly" = 1 ]; then |
207 | non_main='' | |
208 | else | |
209 | non_main=' contrib non-free' | |
210 | fi | |
211 | ||
177f2cd2 | 212 | cat >> "${rootfs}/etc/apt/sources.list" << EOF |
c2a85d04 | 213 | ${prefix} $MIRROR ${release} main${non_main} |
d203007e AT |
214 | EOF |
215 | ||
216 | if [ "$release" != "unstable" -a "$release" != "sid" ]; then | |
217 | cat >> "${rootfs}/etc/apt/sources.list" << EOF | |
c2a85d04 | 218 | ${prefix} $SECURITY_MIRROR ${release}/updates main${non_main} |
177f2cd2 | 219 | EOF |
d203007e | 220 | fi |
177f2cd2 AD |
221 | } |
222 | ||
223 | install_packages() | |
224 | { | |
225 | local rootfs="$1"; shift | |
226 | local packages="$*" | |
227 | ||
bf39edb3 | 228 | chroot "${rootfs}" apt-get update |
177f2cd2 | 229 | if [ -n "${packages}" ]; then |
bf39edb3 | 230 | chroot "${rootfs}" apt-get install --force-yes -y --no-install-recommends ${packages} |
177f2cd2 AD |
231 | fi |
232 | } | |
233 | ||
a9bf60ba AT |
234 | configure_debian_systemd() |
235 | { | |
236 | path=$1 | |
237 | rootfs=$2 | |
a3d42f4b AP |
238 | config=$3 |
239 | num_tty=$4 | |
2b75b644 | 240 | |
2b75b644 | 241 | # just in case systemd is not installed |
c45df3b8 | 242 | mkdir -p "${rootfs}/lib/systemd/system" |
bf39edb3 | 243 | mkdir -p "${rootfs}/etc/systemd/system/getty.target.wants" |
a9bf60ba | 244 | |
19fcf68f | 245 | # Fix getty-static-service as debootstrap does not install dbus |
bf39edb3 | 246 | if [ -e "$rootfs//lib/systemd/system/getty-static.service" ] ; then |
ade83cbf AF |
247 | local tty_services |
248 | tty_services=$(for i in $(seq 2 "$num_tty"); do echo -n "getty@tty${i}.service "; done; ) | |
a3d42f4b | 249 | sed 's/ getty@tty.*/'" $tty_services "'/g' \ |
bf39edb3 AF |
250 | "$rootfs/lib/systemd/system/getty-static.service" | \ |
251 | sed 's/\(tty2-tty\)[5-9]/\1'"${num_tty}"'/g' > "$rootfs/etc/systemd/system/getty-static.service" | |
19fcf68f CB |
252 | fi |
253 | ||
a9bf60ba | 254 | # This function has been copied and adapted from lxc-fedora |
bf39edb3 AF |
255 | rm -f "${rootfs}/etc/systemd/system/default.target" |
256 | chroot "${rootfs}" ln -s /dev/null /etc/systemd/system/udev.service | |
257 | chroot "${rootfs}" ln -s /dev/null /etc/systemd/system/systemd-udevd.service | |
258 | chroot "${rootfs}" ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target | |
a3d42f4b | 259 | # Setup getty service on the ttys we are going to allow in the |
fe1c5887 | 260 | # default config. Number should match lxc.tty.max |
bf39edb3 AF |
261 | ( cd "${rootfs}/etc/systemd/system/getty.target.wants" |
262 | for i in $(seq 1 "$num_tty") ; do ln -sf ../getty\@.service getty@tty"${i}".service; done ) | |
a3d42f4b AP |
263 | |
264 | # Since we use static-getty.target; we need to mask container-getty@.service generated by | |
265 | # container-getty-generator, so we don't get multiple instances of agetty running. | |
266 | # See https://github.com/lxc/lxc/issues/520 and https://github.com/lxc/lxc/issues/484 | |
bf39edb3 AF |
267 | ( cd "${rootfs}/etc/systemd/system/getty.target.wants" |
268 | for i in $(seq 0 "$num_tty"); do ln -sf /dev/null container-getty\@"${i}".service; done ) | |
a9bf60ba AT |
269 | |
270 | return 0 | |
271 | } | |
272 | ||
4737d51a LV |
273 | # Check if given path is in a btrfs partition |
274 | is_btrfs() | |
275 | { | |
bf39edb3 | 276 | [ -e "$1" -a "$(stat -f -c '%T' "$1")" = "btrfs" ] |
4737d51a LV |
277 | } |
278 | ||
279 | # Check if given path is the root of a btrfs subvolume | |
280 | is_btrfs_subvolume() | |
281 | { | |
bf39edb3 | 282 | [ -d "$1" -a "$(stat -f -c '%T' "$1")" = "btrfs" -a "$(stat -c '%i' "$1")" -eq 256 ] |
4737d51a LV |
283 | } |
284 | ||
285 | try_mksubvolume() | |
286 | { | |
287 | path=$1 | |
bf39edb3 AF |
288 | [ -d "$path" ] && return 0 |
289 | mkdir -p "$(dirname "$path")" | |
290 | if which btrfs >/dev/null 2>&1 && is_btrfs "$(dirname "$path")"; then | |
291 | btrfs subvolume create "$path" | |
4737d51a | 292 | else |
bf39edb3 | 293 | mkdir -p "$path" |
4737d51a LV |
294 | fi |
295 | } | |
296 | ||
297 | try_rmsubvolume() | |
298 | { | |
299 | path=$1 | |
bf39edb3 AF |
300 | [ -d "$path" ] || return 0 |
301 | if which btrfs >/dev/null 2>&1 && is_btrfs_subvolume "$path"; then | |
302 | btrfs subvolume delete "$path" | |
4737d51a | 303 | else |
bf39edb3 | 304 | rm -rf "$path" |
4737d51a LV |
305 | fi |
306 | } | |
307 | ||
f1ccde27 SH |
308 | cleanup() |
309 | { | |
bf39edb3 AF |
310 | try_rmsubvolume "$cache/partial-$release-$arch" |
311 | try_rmsubvolume "$cache/rootfs-$release-$arch" | |
f1ccde27 SH |
312 | } |
313 | ||
fb7460fe DL |
314 | download_debian() |
315 | { | |
f95776df AT |
316 | case "$release" in |
317 | wheezy) | |
318 | init=sysvinit | |
319 | ;; | |
320 | *) | |
321 | init=init | |
322 | ;; | |
323 | esac | |
fb7460fe | 324 | packages=\ |
f95776df | 325 | $init,\ |
fb7460fe DL |
326 | ifupdown,\ |
327 | locales,\ | |
fb7460fe | 328 | dialog,\ |
06a1e1db | 329 | isc-dhcp-client,\ |
fb7460fe DL |
330 | netbase,\ |
331 | net-tools,\ | |
332 | iproute,\ | |
333 | openssh-server | |
334 | ||
335 | cache=$1 | |
336 | arch=$2 | |
b269b8ad | 337 | release=$3 |
d50cebd6 LV |
338 | interpreter="$4" |
339 | interpreter_path="$5" | |
fb7460fe | 340 | |
f1ccde27 | 341 | trap cleanup EXIT SIGHUP SIGINT SIGTERM |
11438797 SG |
342 | |
343 | # Create the cache | |
344 | mkdir -p "$cache" | |
345 | ||
f16fb156 VD |
346 | # If debian-archive-keyring isn't installed, fetch GPG keys directly |
347 | releasekeyring=/usr/share/keyrings/debian-archive-keyring.gpg | |
348 | if [ ! -f $releasekeyring ]; then | |
349 | releasekeyring="$cache/archive-key.gpg" | |
350 | case $release in | |
f16fb156 VD |
351 | "wheezy") |
352 | gpgkeyname="archive-key-7.0" | |
353 | ;; | |
87eacd4d | 354 | *) |
42139323 | 355 | gpgkeyname="archive-key-8" |
87eacd4d | 356 | ;; |
f16fb156 VD |
357 | esac |
358 | wget https://ftp-master.debian.org/keys/${gpgkeyname}.asc -O - --quiet \ | |
bf39edb3 | 359 | | gpg --import --no-default-keyring --keyring="${releasekeyring}" |
f16fb156 | 360 | fi |
fb7460fe | 361 | # check the mini debian was not already downloaded |
4737d51a | 362 | try_mksubvolume "$cache/partial-$release-$arch" |
fb7460fe | 363 | if [ $? -ne 0 ]; then |
b269b8ad | 364 | echo "Failed to create '$cache/partial-$release-$arch' directory" |
14d9c0f0 | 365 | return 1 |
81f6a40a RT |
366 | fi |
367 | ||
fb7460fe DL |
368 | # download a mini debian into a cache |
369 | echo "Downloading debian minimal ..." | |
d50cebd6 | 370 | if [ "$interpreter" = "" ] ; then |
bf39edb3 AF |
371 | debootstrap --verbose --variant=minbase --arch="$arch" \ |
372 | --include=$packages --keyring="${releasekeyring}" \ | |
373 | "$release" "$cache/partial-$release-$arch" "$MIRROR" | |
d50cebd6 LV |
374 | if [ $? -ne 0 ]; then |
375 | echo "Failed to download the rootfs, aborting." | |
376 | return 1 | |
377 | fi | |
378 | else | |
bf39edb3 AF |
379 | debootstrap --foreign --verbose --variant=minbase --arch="$arch" \ |
380 | --include=$packages --keyring="${releasekeyring}" \ | |
381 | "$release" "$cache/partial-$release-$arch" "$MIRROR" | |
d50cebd6 LV |
382 | if [ $? -ne 0 ]; then |
383 | echo "Failed to download the rootfs, aborting." | |
384 | return 1 | |
385 | fi | |
bf39edb3 | 386 | mkdir -p "$(basename "$cache/partial-$release-$arch/$interpreter_path")" |
d50cebd6 LV |
387 | cp "$interpreter" "$cache/partial-$release-$arch/$interpreter_path" |
388 | if [ $? -ne 0 ]; then | |
389 | echo "failed to copy $interpreter to $cache/partial-$release-$arch/$interpreter_path" | |
390 | return 1 | |
391 | fi | |
392 | chroot "$cache/partial-$release-$arch" debootstrap/debootstrap --second-stage | |
393 | if [ $? -ne 0 ]; then | |
394 | echo "failed to update the rootfs, aborting" | |
395 | return 1 | |
396 | fi | |
c952d1b9 | 397 | fi |
cd830f33 | 398 | |
b269b8ad | 399 | mv "$1/partial-$release-$arch" "$1/rootfs-$release-$arch" |
fb7460fe | 400 | echo "Download complete." |
f1ccde27 SH |
401 | trap EXIT |
402 | trap SIGINT | |
403 | trap SIGTERM | |
404 | trap SIGHUP | |
cd830f33 | 405 | |
fb7460fe | 406 | return 0 |
c952d1b9 | 407 | } |
bad69158 | 408 | |
fb7460fe | 409 | copy_debian() |
c952d1b9 | 410 | { |
fb7460fe DL |
411 | cache=$1 |
412 | arch=$2 | |
413 | rootfs=$3 | |
b269b8ad | 414 | release=$4 |
bad69158 | 415 | |
fb7460fe DL |
416 | # make a local copy of the minidebian |
417 | echo -n "Copying rootfs to $rootfs..." | |
bf39edb3 | 418 | try_mksubvolume "$rootfs" |
4737d51a LV |
419 | if which btrfs >/dev/null 2>&1 && \ |
420 | is_btrfs_subvolume "$cache/rootfs-$release-$arch" && \ | |
bf39edb3 AF |
421 | is_btrfs_subvolume "$rootfs"; then |
422 | realrootfs="$(dirname "$config")"/rootfs | |
423 | [ "$rootfs" = "$realrootfs" ] || umount "$rootfs" || return 1 | |
424 | btrfs subvolume delete "$realrootfs" || return 1 | |
425 | btrfs subvolume snapshot "$cache/rootfs-$release-$arch" "$realrootfs" || return 1 | |
426 | [ "$rootfs" = "$realrootfs" ] || mount --bind "$realrootfs" "$rootfs" || return 1 | |
4737d51a | 427 | else |
6273aef1 | 428 | rsync -SHaAX "$cache/rootfs-$release-$arch"/ $rootfs/ || return 1 |
4737d51a | 429 | fi |
fb7460fe | 430 | return 0 |
c952d1b9 | 431 | } |
432 | ||
fb7460fe DL |
433 | install_debian() |
434 | { | |
fb7460fe | 435 | rootfs=$1 |
b269b8ad | 436 | release=$2 |
1927a6be | 437 | arch=$3 |
6dc6f80b | 438 | cache="$4/debian" |
d50cebd6 LV |
439 | interpreter="$5" |
440 | interpreter_path="$6" | |
6ffa3291 | 441 | flushcache=$7 |
00fe5e1d | 442 | mkdir -p $LOCALSTATEDIR/lock/subsys/ |
fb7460fe | 443 | ( |
17abf278 | 444 | flock -x 9 |
14d9c0f0 SG |
445 | if [ $? -ne 0 ]; then |
446 | echo "Cache repository is busy." | |
447 | return 1 | |
448 | fi | |
7afc269d | 449 | |
bf39edb3 | 450 | if [ "$flushcache" -eq 1 ]; then |
6ffa3291 LV |
451 | echo "Flushing cache..." |
452 | cleanup | |
453 | fi | |
454 | ||
b269b8ad LV |
455 | echo "Checking cache download in $cache/rootfs-$release-$arch ... " |
456 | if [ ! -e "$cache/rootfs-$release-$arch" ]; then | |
bf39edb3 | 457 | download_debian "$cache" "$arch" "$release" "$interpreter" "$interpreter_path" |
14d9c0f0 SG |
458 | if [ $? -ne 0 ]; then |
459 | echo "Failed to download 'debian base'" | |
460 | return 1 | |
461 | fi | |
462 | fi | |
c952d1b9 | 463 | |
bf39edb3 | 464 | copy_debian "$cache" "$arch" "$rootfs" "$release" |
14d9c0f0 SG |
465 | if [ $? -ne 0 ]; then |
466 | echo "Failed to copy rootfs" | |
467 | return 1 | |
468 | fi | |
c952d1b9 | 469 | |
14d9c0f0 | 470 | return 0 |
c952d1b9 | 471 | |
00fe5e1d | 472 | ) 9>$LOCALSTATEDIR/lock/subsys/lxc-debian |
85cbaa06 | 473 | |
fb7460fe | 474 | return $? |
bad69158 | 475 | } |
476 | ||
fb7460fe DL |
477 | copy_configuration() |
478 | { | |
479 | path=$1 | |
480 | rootfs=$2 | |
16501521 | 481 | hostname=$3 |
1927a6be | 482 | arch=$4 |
a3d42f4b | 483 | num_tty=$5 |
bad69158 | 484 | |
00fe5e1d | 485 | # Generate the configuration file |
aea1cd3c SG |
486 | # if there is exactly one veth network entry, make sure it has an |
487 | # associated hwaddr. | |
7fa3f2e9 | 488 | nics=$(grep -ce '^lxc\.net\.0\.type[ \t]*=[ \t]*veth' "$path/config") |
bf39edb3 | 489 | if [ "$nics" -eq 1 ]; then |
7fa3f2e9 | 490 | grep -q "^lxc.net.0.hwaddr" "$path/config" || sed -i -e "/^lxc\.net\.0\.type[ \t]*=[ \t]*veth/a lxc.net.0.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')" "$path/config" |
aea1cd3c SG |
491 | fi |
492 | ||
00fe5e1d | 493 | ## Add all the includes |
bf39edb3 AF |
494 | echo "" >> "$path/config" |
495 | echo "# Common configuration" >> "$path/config" | |
00fe5e1d | 496 | if [ -e "${LXC_TEMPLATE_CONFIG}/debian.common.conf" ]; then |
bf39edb3 | 497 | echo "lxc.include = ${LXC_TEMPLATE_CONFIG}/debian.common.conf" >> "$path/config" |
00fe5e1d SG |
498 | fi |
499 | if [ -e "${LXC_TEMPLATE_CONFIG}/debian.${release}.conf" ]; then | |
bf39edb3 | 500 | echo "lxc.include = ${LXC_TEMPLATE_CONFIG}/debian.${release}.conf" >> "$path/config" |
00fe5e1d SG |
501 | fi |
502 | ||
503 | ## Add the container-specific config | |
bf39edb3 AF |
504 | echo "" >> "$path/config" |
505 | echo "# Container specific configuration" >> "$path/config" | |
7a96a068 | 506 | grep -q "^lxc.rootfs.path" "$path/config" 2> /dev/null || echo "lxc.rootfs.path = $rootfs" >> "$path/config" |
00fe5e1d | 507 | |
fb7460fe | 508 | cat <<EOF >> $path/config |
fe1c5887 | 509 | lxc.tty.max = $num_tty |
b67771bc | 510 | lxc.uts.name = $hostname |
00fe5e1d | 511 | lxc.arch = $arch |
232763d6 | 512 | lxc.pty.max = 1024 |
fb7460fe | 513 | EOF |
bad69158 | 514 | |
fb7460fe | 515 | if [ $? -ne 0 ]; then |
14d9c0f0 SG |
516 | echo "Failed to add configuration" |
517 | return 1 | |
bad69158 | 518 | fi |
519 | ||
520 | return 0 | |
521 | } | |
522 | ||
177f2cd2 AD |
523 | post_process() |
524 | { | |
525 | local rootfs="$1"; shift | |
526 | local release="$1"; shift | |
527 | local arch="$1"; shift | |
528 | local hostarch="$1"; shift | |
d50cebd6 | 529 | local interpreter="$1"; shift |
177f2cd2 AD |
530 | local packages="$*" |
531 | ||
532 | # Disable service startup | |
bf39edb3 | 533 | cat > "${rootfs}/usr/sbin/policy-rc.d" << EOF |
177f2cd2 AD |
534 | #!/bin/sh |
535 | exit 101 | |
536 | EOF | |
bf39edb3 | 537 | chmod +x "${rootfs}/usr/sbin/policy-rc.d" |
177f2cd2 AD |
538 | |
539 | # If the container isn't running a native architecture, setup multiarch | |
d50cebd6 | 540 | if [ "$interpreter" = "" -a "${arch}" != "${hostarch}" ]; then |
28e58a6a | 541 | # Test if dpkg supports multiarch |
7d4c775a | 542 | if ! chroot "$rootfs" dpkg --print-foreign-architectures 2>&1; then |
bf39edb3 | 543 | chroot "$rootfs" dpkg --add-architecture "${hostarch}" |
28e58a6a | 544 | fi |
177f2cd2 AD |
545 | fi |
546 | ||
547 | # Write a new sources.list containing both native and multiarch entries | |
bf39edb3 | 548 | > "${rootfs}/etc/apt/sources.list" |
d50cebd6 | 549 | if [ "$interpreter" != "" -a "${arch}" = "${hostarch}" ]; then |
bf39edb3 | 550 | write_sourceslist "${rootfs}" "${release}" "${arch}" |
177f2cd2 | 551 | else |
bf39edb3 | 552 | write_sourceslist "${rootfs}" "${release}" |
177f2cd2 AD |
553 | fi |
554 | ||
555 | # Install Packages in container | |
556 | if [ -n "${packages}" ]; then | |
ade83cbf AF |
557 | local pack_list |
558 | pack_list="${packages//,/ }" | |
177f2cd2 | 559 | echo "Installing packages: ${pack_list}" |
bf39edb3 | 560 | install_packages "${rootfs}" "${pack_list}" |
177f2cd2 AD |
561 | fi |
562 | ||
563 | # Re-enable service startup | |
bf39edb3 | 564 | rm "${rootfs}/usr/sbin/policy-rc.d" |
114eb32f | 565 | |
114eb32f | 566 | # end |
177f2cd2 AD |
567 | } |
568 | ||
fb7460fe DL |
569 | clean() |
570 | { | |
6dc6f80b | 571 | cache=${LXC_CACHE_PATH:-"$LOCALSTATEDIR/cache/lxc/debian"} |
bad69158 | 572 | |
bf39edb3 | 573 | if [ ! -e "$cache" ]; then |
14d9c0f0 | 574 | exit 0 |
bad69158 | 575 | fi |
576 | ||
577 | # lock, so we won't purge while someone is creating a repository | |
578 | ( | |
17abf278 | 579 | flock -x 9 |
14d9c0f0 SG |
580 | if [ $? != 0 ]; then |
581 | echo "Cache repository is busy." | |
582 | exit 1 | |
583 | fi | |
bad69158 | 584 | |
14d9c0f0 | 585 | echo -n "Purging the download cache..." |
bf39edb3 | 586 | rm --preserve-root --one-file-system -rf "$cache" && echo "Done." || exit 1 |
14d9c0f0 | 587 | exit 0 |
bad69158 | 588 | |
00fe5e1d | 589 | ) 9>$LOCALSTATEDIR/lock/subsys/lxc-debian |
bad69158 | 590 | } |
591 | ||
fb7460fe DL |
592 | usage() |
593 | { | |
594 | cat <<EOF | |
9cbffb9f TP |
595 | Template specific options can be passed to lxc-create after a '--' like this: |
596 | ||
597 | lxc-create --name=NAME [-lxc-create-options] -- [-template-options] | |
598 | ||
599 | Usage: $1 -h|--help -p|--path=<path> [-c|--clean] [-a|--arch=<arch>] [-r|--release=<release>] | |
600 | [--mirror=<mirror>] [--security-mirror=<security mirror>] | |
601 | [--package=<package_name1,package_name2,...>] | |
d50cebd6 | 602 | [-I|--interpreter-path=<interpreter path>] |
9b6fb5d4 | 603 | [-F | --flush-cache] [-S|--auth-key=<keyfile>] |
9cbffb9f TP |
604 | |
605 | Options : | |
606 | ||
607 | -h, --help print this help text | |
608 | -p, --path=PATH directory where config and rootfs of this VM will be kept | |
9b6fb5d4 | 609 | -S, --auth-key=KEYFILE SSH public key to inject into the container as the root user. |
9cbffb9f TP |
610 | -a, --arch=ARCH The container architecture. Can be one of: i686, x86_64, |
611 | amd64, armhf, armel, powerpc. Defaults to host arch. | |
52c5ac5f | 612 | -r, --release=RELEASE Debian release. Can be one of: wheezy, jessie, stretch, buster, sid. |
9cbffb9f TP |
613 | Defaults to current stable. |
614 | --mirror=MIRROR Debian mirror to use during installation. Overrides the MIRROR | |
615 | environment variable (see below). | |
616 | --security-mirror=SECURITY_MIRROR | |
617 | Debian mirror to use for security updates. Overrides the | |
618 | SECURITY_MIRROR environment variable (see below). | |
619 | --packages=PACKAGE_NAME1,PACKAGE_NAME2,... | |
620 | List of additional packages to install. Comma separated, without space. | |
621 | -c, --clean only clean up the cache and terminate | |
57b40c08 | 622 | --enable-non-free include also Debian's contrib and non-free repositories. |
d50cebd6 LV |
623 | -I|--interpreter-path=INTERPRETER-PATH |
624 | Path of the binfmt interpreter to copy to the rootfs | |
6ffa3291 | 625 | -F | --flush-cache Flush the debian release cache |
9cbffb9f TP |
626 | |
627 | Environment variables: | |
628 | ||
629 | MIRROR The Debian package mirror to use. See also the --mirror switch above. | |
630 | Defaults to '$MIRROR' | |
631 | SECURITY_MIRROR The Debian package security mirror to use. See also the --security-mirror switch above. | |
632 | Defaults to '$SECURITY_MIRROR' | |
633 | ||
fb7460fe DL |
634 | EOF |
635 | return 0 | |
636 | } | |
637 | ||
9b6fb5d4 | 638 | options=$(getopt -o hp:n:a:r:cI:FS: -l arch:,auth-key:,clean,help,enable-non-free,mirror:,name:,packages:,path:,release:,rootfs:,security-mirror:,interpreter-path:,flush-cache -- "$@") |
fb7460fe | 639 | if [ $? -ne 0 ]; then |
bf39edb3 | 640 | usage "$(basename "$0")" |
14d9c0f0 | 641 | exit 1 |
fb7460fe DL |
642 | fi |
643 | eval set -- "$options" | |
644 | ||
6f943dd9 JC |
645 | littleendian=$(lscpu | grep '^Byte Order' | grep -q Little && echo yes) |
646 | ||
4963978b SG |
647 | arch=$(uname -m) |
648 | if [ "$arch" = "i686" ]; then | |
649 | arch="i386" | |
650 | elif [ "$arch" = "x86_64" ]; then | |
651 | arch="amd64" | |
652 | elif [ "$arch" = "armv7l" ]; then | |
653 | arch="armhf" | |
2c660503 EG |
654 | elif [ "$arch" = "aarch64" ]; then |
655 | arch="arm64" | |
944d1191 SRR |
656 | elif [ "$arch" = "ppc" ]; then |
657 | arch="powerpc" | |
bfbf7936 TF |
658 | elif [ "$arch" = "ppc64le" ]; then |
659 | arch="ppc64el" | |
6f943dd9 JC |
660 | elif [ "$arch" = "mips" -a "$littleendian" = "yes" ]; then |
661 | arch="mipsel" | |
662 | elif [ "$arch" = "mips64" -a "$littleendian" = "yes" ]; then | |
663 | arch="mips64el" | |
1927a6be LV |
664 | fi |
665 | hostarch=$arch | |
57b40c08 | 666 | mainonly=1 |
6ffa3291 | 667 | flushcache=0 |
1927a6be | 668 | |
fb7460fe DL |
669 | while true |
670 | do | |
671 | case "$1" in | |
bf39edb3 | 672 | -h|--help) usage "$0" && exit 1;; |
177f2cd2 AD |
673 | --) shift 1; break ;; |
674 | ||
675 | -a|--arch) arch=$2; shift 2;; | |
9b6fb5d4 | 676 | -S|--auth-key) authkey=$2; shift 2;; |
d50cebd6 LV |
677 | -I|--interpreter-path) |
678 | interpreter="$2"; shift 2;; | |
e4d4da62 | 679 | -c|--clean) clean=1; shift 1;; |
57b40c08 | 680 | --enable-non-free) mainonly=0; shift 1;; |
177f2cd2 AD |
681 | --mirror) MIRROR=$2; shift 2;; |
682 | -n|--name) name=$2; shift 2;; | |
683 | --packages) packages=$2; shift 2;; | |
684 | -p|--path) path=$2; shift 2;; | |
685 | -r|--release) release=$2; shift 2;; | |
686 | --rootfs) rootfs=$2; shift 2;; | |
687 | --security-mirror) SECURITY_MIRROR=$2; shift 2;; | |
6ffa3291 | 688 | -F|--flush-cache) flushcache=1; shift 1;; |
177f2cd2 | 689 | *) break ;; |
fb7460fe DL |
690 | esac |
691 | done | |
692 | ||
693 | if [ ! -z "$clean" -a -z "$path" ]; then | |
694 | clean || exit 1 | |
695 | exit 0 | |
696 | fi | |
697 | ||
17abf278 | 698 | if [ "$arch" = "i686" ]; then |
1927a6be LV |
699 | arch=i386 |
700 | fi | |
701 | ||
17abf278 | 702 | if [ "$arch" = "x86_64" ]; then |
1927a6be LV |
703 | arch=amd64 |
704 | fi | |
705 | ||
d50cebd6 LV |
706 | if [ "$interpreter" = "" ] ; then |
707 | if [ $hostarch = "i386" -a $arch = "amd64" ]; then | |
708 | echo "can't create $arch container on $hostarch" | |
709 | exit 1 | |
710 | fi | |
1927a6be | 711 | |
d50cebd6 LV |
712 | if [ $hostarch = "armhf" -o $hostarch = "armel" ] && \ |
713 | [ $arch != "armhf" -a $arch != "armel" ]; then | |
714 | echo "can't create $arch container on $hostarch" | |
715 | exit 1 | |
716 | fi | |
1927a6be | 717 | |
d50cebd6 LV |
718 | if [ $hostarch = "powerpc" -a $arch != "powerpc" ]; then |
719 | echo "can't create $arch container on $hostarch" | |
720 | exit 1 | |
721 | fi | |
6f943dd9 JC |
722 | |
723 | if [ $hostarch = "mips" -a $arch != "mips" ] || \ | |
724 | [ $hostarch = "mipsel" -a $arch != "mipsel" ] || \ | |
725 | [ $hostarch = "mips64" -a $arch != "mips" -a $arch != "mips64" ] || \ | |
726 | [ $hostarch = "mips64el" -a $arch != "mipsel" -a $arch != "mips64el" ]; then | |
727 | echo "can't create $arch container on $hostarch" | |
728 | exit 1 | |
729 | fi | |
d50cebd6 LV |
730 | else |
731 | if ! file -b "${interpreter}" |grep -q "statically linked" ; then | |
732 | echo "'${interpreter}' must be statically linked" 1>&2 | |
733 | exit 1 | |
734 | fi | |
735 | interpreter_path=$(find_interpreter "$interpreter") | |
736 | if [ $? -ne 0 ] ; then | |
bf39edb3 | 737 | echo "no binfmt interpreter using $(basename "$interpreter")" 1>&2 |
d50cebd6 LV |
738 | exit 1 |
739 | fi | |
1927a6be LV |
740 | fi |
741 | ||
fb7460fe DL |
742 | type debootstrap |
743 | if [ $? -ne 0 ]; then | |
744 | echo "'debootstrap' command is missing" | |
745 | exit 1 | |
746 | fi | |
747 | ||
748 | if [ -z "$path" ]; then | |
749 | echo "'path' parameter is required" | |
750 | exit 1 | |
751 | fi | |
752 | ||
753 | if [ "$(id -u)" != "0" ]; then | |
754 | echo "This script should be run as 'root'" | |
755 | exit 1 | |
c01d62f2 | 756 | fi |
bad69158 | 757 | |
9b6fb5d4 BJ |
758 | if [ -n "$authkey" ]; then |
759 | if [ ! -f "$authkey" ]; then | |
760 | echo "SSH keyfile '$authkey' not found" | |
761 | exit 1 | |
762 | fi | |
763 | # This is mostly to prevent accidental uage of the private key instead | |
764 | # of the public key. | |
765 | if [ "${authkey: -4}" != ".pub" ]; then | |
766 | echo "SSH keyfile '$authkey' does not end with '.pub'" | |
767 | exit 1 | |
768 | fi | |
769 | fi | |
770 | ||
dba285d5 AT |
771 | release=${release:-stable} |
772 | permanent_releases=('stable' 'testing' 'sid' 'unstable') | |
773 | if [[ ! "${permanent_releases[*]}" =~ (^|[^[:alpha:]])$release([^[:alpha:]]|$) ]]; then | |
774 | if ! wget "${MIRROR}/dists/${release}/Release" -O /dev/null 2> /dev/null; then | |
775 | echo "Invalid release ${release} (not found in mirror)" | |
776 | exit 1 | |
777 | fi | |
b269b8ad LV |
778 | fi |
779 | ||
1881820a SH |
780 | # detect rootfs |
781 | config="$path/config" | |
1897e3bc | 782 | if [ -z "$rootfs" ]; then |
7a96a068 CB |
783 | if grep -q '^lxc.rootfs.path' "$config" 2> /dev/null ; then |
784 | rootfs=$(awk -F= '/^lxc.rootfs.path[ \t]+=/{ print $2 }' "$config") | |
1897e3bc SH |
785 | else |
786 | rootfs=$path/rootfs | |
787 | fi | |
1881820a SH |
788 | fi |
789 | ||
a3d42f4b | 790 | # determine the number of ttys - default is 4 |
fe1c5887 CB |
791 | if grep -q '^lxc.tty.max' "$config" 2> /dev/null ; then |
792 | num_tty=$(awk -F= '/^lxc.tty.max[ \t]+=/{ print $2 }' "$config") | |
a3d42f4b AP |
793 | else |
794 | num_tty=4 | |
795 | fi | |
796 | ||
bf39edb3 | 797 | install_debian "$rootfs" "$release" "$arch" "$LXC_CACHE_PATH" "$interpreter" "$interpreter_path" "$flushcache" |
fb7460fe DL |
798 | if [ $? -ne 0 ]; then |
799 | echo "failed to install debian" | |
800 | exit 1 | |
801 | fi | |
802 | ||
bf39edb3 | 803 | configure_debian "$rootfs" "$name" $num_tty |
fb7460fe DL |
804 | if [ $? -ne 0 ]; then |
805 | echo "failed to configure debian for a container" | |
806 | exit 1 | |
807 | fi | |
808 | ||
bf39edb3 | 809 | copy_configuration "$path" "$rootfs" "$name" $arch $num_tty |
fb7460fe DL |
810 | if [ $? -ne 0 ]; then |
811 | echo "failed write configuration file" | |
812 | exit 1 | |
813 | fi | |
814 | ||
bf39edb3 | 815 | configure_debian_systemd "$path" "$rootfs" "$config" $num_tty |
a9bf60ba | 816 | |
bf39edb3 | 817 | post_process "${rootfs}" "${release}" ${arch} ${hostarch} "${interpreter}" "${packages}" |
177f2cd2 | 818 | |
227c5600 | 819 | if [ ! -z "$clean" ]; then |
fb7460fe DL |
820 | clean || exit 1 |
821 | exit 0 | |
822 | fi |