]>
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 | |
49a630b8 | 23 | MIRROR=${MIRROR:-http://cdn.debian.net/debian} |
2a7c16dc | 24 | |
fb7460fe DL |
25 | configure_debian() |
26 | { | |
27 | rootfs=$1 | |
28 | hostname=$2 | |
29 | ||
4e0eb765 DB |
30 | # squeeze only has /dev/tty and /dev/tty0 by default, |
31 | # therefore creating missing device nodes for tty1-4. | |
32 | for tty in $(seq 1 4); do | |
14d9c0f0 SG |
33 | if [ ! -e $rootfs/dev/tty$tty ]; then |
34 | mknod $rootfs/dev/tty$tty c 4 $tty | |
35 | fi | |
4e0eb765 DB |
36 | done |
37 | ||
fb7460fe DL |
38 | # configure the inittab |
39 | cat <<EOF > $rootfs/etc/inittab | |
06388011 | 40 | id:3:initdefault: |
41 | si::sysinit:/etc/init.d/rcS | |
42 | l0:0:wait:/etc/init.d/rc 0 | |
43 | l1:1:wait:/etc/init.d/rc 1 | |
44 | l2:2:wait:/etc/init.d/rc 2 | |
45 | l3:3:wait:/etc/init.d/rc 3 | |
46 | l4:4:wait:/etc/init.d/rc 4 | |
47 | l5:5:wait:/etc/init.d/rc 5 | |
48 | l6:6:wait:/etc/init.d/rc 6 | |
49 | # Normally not reached, but fallthrough in case of emergency. | |
50 | z6:6:respawn:/sbin/sulogin | |
51 | 1:2345:respawn:/sbin/getty 38400 console | |
b0a33c1e | 52 | c1:12345:respawn:/sbin/getty 38400 tty1 linux |
53 | c2:12345:respawn:/sbin/getty 38400 tty2 linux | |
54 | c3:12345:respawn:/sbin/getty 38400 tty3 linux | |
55 | c4:12345:respawn:/sbin/getty 38400 tty4 linux | |
f79d43bb | 56 | p6::ctrlaltdel:/sbin/init 6 |
6bf8daf9 | 57 | p0::powerfail:/sbin/init 0 |
06388011 | 58 | EOF |
06388011 | 59 | |
fb7460fe DL |
60 | # disable selinux in debian |
61 | mkdir -p $rootfs/selinux | |
62 | echo 0 > $rootfs/selinux/enforce | |
06388011 | 63 | |
fb7460fe DL |
64 | # configure the network using the dhcp |
65 | cat <<EOF > $rootfs/etc/network/interfaces | |
66 | auto lo | |
67 | iface lo inet loopback | |
06388011 | 68 | |
fb7460fe DL |
69 | auto eth0 |
70 | iface eth0 inet dhcp | |
06388011 | 71 | EOF |
1846e71a | 72 | |
fb7460fe DL |
73 | # set the hostname |
74 | cat <<EOF > $rootfs/etc/hostname | |
75 | $hostname | |
76 | EOF | |
06388011 | 77 | |
fb7460fe | 78 | # reconfigure some services |
f1fa1a08 | 79 | if [ -z "$LANG" ]; then |
14d9c0f0 SG |
80 | chroot $rootfs locale-gen en_US.UTF-8 UTF-8 |
81 | chroot $rootfs update-locale LANG=en_US.UTF-8 | |
f1fa1a08 | 82 | else |
90ccc878 | 83 | encoding=$(echo $LANG | cut -d. -f2) |
09da66e6 | 84 | chroot $rootfs sed -e "s/^# \(${LANG} ${encoding}\)/\1/" \ |
90ccc878 LV |
85 | -i /etc/locale.gen 2>/dev/null |
86 | chroot $rootfs locale-gen $LANG $encoding | |
14d9c0f0 | 87 | chroot $rootfs update-locale LANG=$LANG |
f1fa1a08 | 88 | fi |
06388011 | 89 | |
fb7460fe | 90 | # remove pointless services in a container |
7593bdfb | 91 | chroot $rootfs /usr/sbin/update-rc.d -f checkroot.sh remove |
fb7460fe DL |
92 | chroot $rootfs /usr/sbin/update-rc.d -f umountfs remove |
93 | chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh remove | |
94 | chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh remove | |
19d618b1 | 95 | |
f7365a24 | 96 | # set initial timezone as on host |
97 | if [ -f /etc/timezone ]; then | |
0a3673e8 | 98 | cat /etc/timezone > $rootfs/etc/timezone |
f7365a24 | 99 | chroot $rootfs dpkg-reconfigure -f noninteractive tzdata |
100 | elif [ -f /etc/sysconfig/clock ]; then | |
17abf278 | 101 | . /etc/sysconfig/clock |
f7365a24 | 102 | echo $ZONE > $rootfs/etc/timezone |
103 | chroot $rootfs dpkg-reconfigure -f noninteractive tzdata | |
104 | else | |
105 | echo "Timezone in container is not configured. Adjust it manually." | |
106 | fi | |
107 | ||
19d618b1 DL |
108 | echo "root:root" | chroot $rootfs chpasswd |
109 | echo "Root password is 'root', please change !" | |
110 | ||
111 | return 0 | |
06388011 | 112 | } |
113 | ||
f1ccde27 SH |
114 | cleanup() |
115 | { | |
b269b8ad LV |
116 | rm -rf $cache/partial-$release-$arch |
117 | rm -rf $cache/rootfs-$release-$arch | |
f1ccde27 SH |
118 | } |
119 | ||
fb7460fe DL |
120 | download_debian() |
121 | { | |
122 | packages=\ | |
123 | ifupdown,\ | |
124 | locales,\ | |
125 | libui-dialog-perl,\ | |
126 | dialog,\ | |
06a1e1db | 127 | isc-dhcp-client,\ |
fb7460fe DL |
128 | netbase,\ |
129 | net-tools,\ | |
130 | iproute,\ | |
131 | openssh-server | |
132 | ||
133 | cache=$1 | |
134 | arch=$2 | |
b269b8ad | 135 | release=$3 |
fb7460fe | 136 | |
f1ccde27 | 137 | trap cleanup EXIT SIGHUP SIGINT SIGTERM |
fb7460fe | 138 | # check the mini debian was not already downloaded |
b269b8ad | 139 | mkdir -p "$cache/partial-$release-$arch" |
fb7460fe | 140 | if [ $? -ne 0 ]; then |
b269b8ad | 141 | echo "Failed to create '$cache/partial-$release-$arch' directory" |
14d9c0f0 | 142 | return 1 |
81f6a40a RT |
143 | fi |
144 | ||
fb7460fe DL |
145 | # download a mini debian into a cache |
146 | echo "Downloading debian minimal ..." | |
147 | debootstrap --verbose --variant=minbase --arch=$arch \ | |
14d9c0f0 | 148 | --include=$packages \ |
b269b8ad | 149 | "$release" "$cache/partial-$release-$arch" $MIRROR |
fb7460fe | 150 | if [ $? -ne 0 ]; then |
14d9c0f0 SG |
151 | echo "Failed to download the rootfs, aborting." |
152 | return 1 | |
c952d1b9 | 153 | fi |
cd830f33 | 154 | |
b269b8ad | 155 | mv "$1/partial-$release-$arch" "$1/rootfs-$release-$arch" |
fb7460fe | 156 | echo "Download complete." |
f1ccde27 SH |
157 | trap EXIT |
158 | trap SIGINT | |
159 | trap SIGTERM | |
160 | trap SIGHUP | |
cd830f33 | 161 | |
fb7460fe | 162 | return 0 |
c952d1b9 | 163 | } |
bad69158 | 164 | |
fb7460fe | 165 | copy_debian() |
c952d1b9 | 166 | { |
fb7460fe DL |
167 | cache=$1 |
168 | arch=$2 | |
169 | rootfs=$3 | |
b269b8ad | 170 | release=$4 |
bad69158 | 171 | |
fb7460fe DL |
172 | # make a local copy of the minidebian |
173 | echo -n "Copying rootfs to $rootfs..." | |
6d8ac56b | 174 | mkdir -p $rootfs |
b269b8ad | 175 | rsync -Ha "$cache/rootfs-$release-$arch"/ $rootfs/ || return 1 |
fb7460fe | 176 | return 0 |
c952d1b9 | 177 | } |
178 | ||
fb7460fe DL |
179 | install_debian() |
180 | { | |
181 | cache="@LOCALSTATEDIR@/cache/lxc/debian" | |
182 | rootfs=$1 | |
b269b8ad | 183 | release=$2 |
1927a6be | 184 | arch=$3 |
fb7460fe DL |
185 | mkdir -p @LOCALSTATEDIR@/lock/subsys/ |
186 | ( | |
17abf278 | 187 | flock -x 9 |
14d9c0f0 SG |
188 | if [ $? -ne 0 ]; then |
189 | echo "Cache repository is busy." | |
190 | return 1 | |
191 | fi | |
7afc269d | 192 | |
b269b8ad LV |
193 | echo "Checking cache download in $cache/rootfs-$release-$arch ... " |
194 | if [ ! -e "$cache/rootfs-$release-$arch" ]; then | |
195 | download_debian $cache $arch $release | |
14d9c0f0 SG |
196 | if [ $? -ne 0 ]; then |
197 | echo "Failed to download 'debian base'" | |
198 | return 1 | |
199 | fi | |
200 | fi | |
c952d1b9 | 201 | |
b269b8ad | 202 | copy_debian $cache $arch $rootfs $release |
14d9c0f0 SG |
203 | if [ $? -ne 0 ]; then |
204 | echo "Failed to copy rootfs" | |
205 | return 1 | |
206 | fi | |
c952d1b9 | 207 | |
14d9c0f0 | 208 | return 0 |
c952d1b9 | 209 | |
17abf278 | 210 | ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-debian |
85cbaa06 | 211 | |
fb7460fe | 212 | return $? |
bad69158 | 213 | } |
214 | ||
fb7460fe DL |
215 | copy_configuration() |
216 | { | |
217 | path=$1 | |
218 | rootfs=$2 | |
16501521 | 219 | hostname=$3 |
1927a6be | 220 | arch=$4 |
bad69158 | 221 | |
aea1cd3c SG |
222 | # if there is exactly one veth network entry, make sure it has an |
223 | # associated hwaddr. | |
224 | nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l` | |
225 | if [ $nics -eq 1 ]; then | |
226 | 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 | |
227 | fi | |
228 | ||
1881820a | 229 | grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config |
fb7460fe DL |
230 | cat <<EOF >> $path/config |
231 | lxc.tty = 4 | |
232 | lxc.pts = 1024 | |
1927a6be | 233 | lxc.arch = $arch |
16501521 | 234 | lxc.utsname = $hostname |
eee3ba81 | 235 | lxc.cap.drop = sys_module mac_admin mac_override sys_time |
f02ce27d SG |
236 | |
237 | # When using LXC with apparmor, uncomment the next line to run unconfined: | |
238 | #lxc.aa_profile = unconfined | |
239 | ||
fb7460fe DL |
240 | lxc.cgroup.devices.deny = a |
241 | # /dev/null and zero | |
242 | lxc.cgroup.devices.allow = c 1:3 rwm | |
243 | lxc.cgroup.devices.allow = c 1:5 rwm | |
244 | # consoles | |
245 | lxc.cgroup.devices.allow = c 5:1 rwm | |
246 | lxc.cgroup.devices.allow = c 5:0 rwm | |
247 | lxc.cgroup.devices.allow = c 4:0 rwm | |
248 | lxc.cgroup.devices.allow = c 4:1 rwm | |
249 | # /dev/{,u}random | |
250 | lxc.cgroup.devices.allow = c 1:9 rwm | |
251 | lxc.cgroup.devices.allow = c 1:8 rwm | |
252 | lxc.cgroup.devices.allow = c 136:* rwm | |
253 | lxc.cgroup.devices.allow = c 5:2 rwm | |
254 | # rtc | |
eee3ba81 | 255 | lxc.cgroup.devices.allow = c 254:0 rm |
a7dff834 DL |
256 | |
257 | # mounts point | |
eba7df9e SG |
258 | lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0 |
259 | lxc.mount.entry = sysfs sys sysfs defaults 0 0 | |
fb7460fe | 260 | EOF |
bad69158 | 261 | |
fb7460fe | 262 | if [ $? -ne 0 ]; then |
14d9c0f0 SG |
263 | echo "Failed to add configuration" |
264 | return 1 | |
bad69158 | 265 | fi |
266 | ||
267 | return 0 | |
268 | } | |
269 | ||
fb7460fe DL |
270 | clean() |
271 | { | |
272 | cache="@LOCALSTATEDIR@/cache/lxc/debian" | |
bad69158 | 273 | |
fb7460fe | 274 | if [ ! -e $cache ]; then |
14d9c0f0 | 275 | exit 0 |
bad69158 | 276 | fi |
277 | ||
278 | # lock, so we won't purge while someone is creating a repository | |
279 | ( | |
17abf278 | 280 | flock -x 9 |
14d9c0f0 SG |
281 | if [ $? != 0 ]; then |
282 | echo "Cache repository is busy." | |
283 | exit 1 | |
284 | fi | |
bad69158 | 285 | |
14d9c0f0 SG |
286 | echo -n "Purging the download cache..." |
287 | rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1 | |
288 | exit 0 | |
bad69158 | 289 | |
17abf278 | 290 | ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-debian |
bad69158 | 291 | } |
292 | ||
fb7460fe DL |
293 | usage() |
294 | { | |
295 | cat <<EOF | |
1927a6be LV |
296 | $1 -h|--help -p|--path=<path> [-a|--arch] [-r|--release=<release>] [-c|--clean] |
297 | release: the debian release (e.g. wheezy): defaults to current stable | |
298 | arch: the container architecture (e.g. amd64): defaults to host arch | |
fb7460fe DL |
299 | EOF |
300 | return 0 | |
301 | } | |
302 | ||
1927a6be | 303 | options=$(getopt -o hp:n:a:r:c -l help,rootfs:,path:,name:,arch:,release:,clean -- "$@") |
fb7460fe DL |
304 | if [ $? -ne 0 ]; then |
305 | usage $(basename $0) | |
14d9c0f0 | 306 | exit 1 |
fb7460fe DL |
307 | fi |
308 | eval set -- "$options" | |
309 | ||
1927a6be LV |
310 | if which dpkg >/dev/null 2>&1 ; then |
311 | arch=$(dpkg --print-architecture) | |
312 | else | |
313 | arch=$(uname -m) | |
314 | if [ "$arch" = "i686" ]; then | |
315 | arch="i386" | |
316 | elif [ "$arch" = "x86_64" ]; then | |
317 | arch="amd64" | |
318 | elif [ "$arch" = "armv7l" ]; then | |
319 | arch="armhf" | |
320 | fi | |
321 | fi | |
322 | hostarch=$arch | |
323 | ||
fb7460fe DL |
324 | while true |
325 | do | |
326 | case "$1" in | |
b269b8ad | 327 | -h|--help) usage $0 && exit 1;; |
fb7460fe | 328 | -p|--path) path=$2; shift 2;; |
1897e3bc | 329 | --rootfs) rootfs=$2; shift 2;; |
1927a6be | 330 | -a|--arch) arch=$2; shift 2;; |
b269b8ad | 331 | -r|--release) release=$2; shift 2;; |
14d9c0f0 SG |
332 | -n|--name) name=$2; shift 2;; |
333 | -c|--clean) clean=$2; shift 2;; | |
fb7460fe DL |
334 | --) shift 1; break ;; |
335 | *) break ;; | |
336 | esac | |
337 | done | |
338 | ||
339 | if [ ! -z "$clean" -a -z "$path" ]; then | |
340 | clean || exit 1 | |
341 | exit 0 | |
342 | fi | |
343 | ||
17abf278 | 344 | if [ "$arch" = "i686" ]; then |
1927a6be LV |
345 | arch=i386 |
346 | fi | |
347 | ||
17abf278 | 348 | if [ "$arch" = "x86_64" ]; then |
1927a6be LV |
349 | arch=amd64 |
350 | fi | |
351 | ||
352 | if [ $hostarch = "i386" -a $arch = "amd64" ]; then | |
353 | echo "can't create $arch container on $hostarch" | |
354 | exit 1 | |
355 | fi | |
356 | ||
357 | if [ $hostarch = "armhf" -o $hostarch = "armel" ] && \ | |
358 | [ $arch != "armhf" -a $arch != "armel" ]; then | |
359 | echo "can't create $arch container on $hostarch" | |
360 | exit 1 | |
361 | fi | |
362 | ||
363 | if [ $hostarch = "powerpc" -a $arch != "powerpc" ]; then | |
364 | echo "can't create $arch container on $hostarch" | |
365 | exit 1 | |
366 | fi | |
367 | ||
fb7460fe DL |
368 | type debootstrap |
369 | if [ $? -ne 0 ]; then | |
370 | echo "'debootstrap' command is missing" | |
371 | exit 1 | |
372 | fi | |
373 | ||
374 | if [ -z "$path" ]; then | |
375 | echo "'path' parameter is required" | |
376 | exit 1 | |
377 | fi | |
378 | ||
379 | if [ "$(id -u)" != "0" ]; then | |
380 | echo "This script should be run as 'root'" | |
381 | exit 1 | |
c01d62f2 | 382 | fi |
bad69158 | 383 | |
b269b8ad LV |
384 | current_release=`wget ${MIRROR}/dists/stable/Release -O - 2>/dev/null |\ |
385 | head |awk '/^Codename: (.*)$/ { print $2; }'` | |
386 | release=${release:-${current_release}} | |
387 | valid_releases=('squeeze' 'wheezy' 'jessie' 'sid') | |
388 | if [[ ! "${valid_releases[*]}" =~ (^|[^[:alpha:]])$release([^[:alpha:]]|$) ]] | |
389 | then | |
390 | echo "Invalid release ${release}, valid ones are: ${valid_releases[*]}" | |
391 | exit 1 | |
392 | fi | |
393 | ||
1881820a SH |
394 | # detect rootfs |
395 | config="$path/config" | |
1897e3bc SH |
396 | if [ -z "$rootfs" ]; then |
397 | if grep -q '^lxc.rootfs' $config 2>/dev/null ; then | |
853d58fd | 398 | rootfs=$(awk -F= '/^lxc.rootfs =/{ print $2 }' $config) |
1897e3bc SH |
399 | else |
400 | rootfs=$path/rootfs | |
401 | fi | |
1881820a SH |
402 | fi |
403 | ||
fb7460fe | 404 | |
1927a6be | 405 | install_debian $rootfs $release $arch |
fb7460fe DL |
406 | if [ $? -ne 0 ]; then |
407 | echo "failed to install debian" | |
408 | exit 1 | |
409 | fi | |
410 | ||
411 | configure_debian $rootfs $name | |
412 | if [ $? -ne 0 ]; then | |
413 | echo "failed to configure debian for a container" | |
414 | exit 1 | |
415 | fi | |
416 | ||
1927a6be | 417 | copy_configuration $path $rootfs $name $arch |
fb7460fe DL |
418 | if [ $? -ne 0 ]; then |
419 | echo "failed write configuration file" | |
420 | exit 1 | |
421 | fi | |
422 | ||
423 | if [ ! -z $clean ]; then | |
424 | clean || exit 1 | |
425 | exit 0 | |
426 | fi |