Annotation of /trunk/lxc/lxc-magellan.sh
Parent Directory | Revision Log
Revision 1057 -
(hide annotations)
(download)
(as text)
Tue Jul 13 14:47:25 2010 UTC (14 years, 2 months ago) by niro
File MIME type: application/x-sh
File size: 9102 byte(s)
Tue Jul 13 14:47:25 2010 UTC (14 years, 2 months ago) by niro
File MIME type: application/x-sh
File size: 9102 byte(s)
lxc template script
1 | niro | 1057 | #!/bin/bash |
2 | |||
3 | # | ||
4 | # lxc: linux Container library | ||
5 | |||
6 | # Authors: | ||
7 | # Niels Rogalla <niro@magellan-linux.de> | ||
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 | ||
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | # Lesser General Public License for more details. | ||
18 | |||
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 | ||
21 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | |||
23 | die() { echo "ERROR: $@"; exit 1; } | ||
24 | |||
25 | configure_magellan() | ||
26 | { | ||
27 | local rootfs="$1" | ||
28 | local hostname="$2" | ||
29 | |||
30 | echo "Setting up rootfs..." | ||
31 | |||
32 | # fix locales first | ||
33 | if [[ -z ${LANG} ]] && [[ -z ${LC_ALL} ]] | ||
34 | then | ||
35 | sed -i "s:^#\(en_US..*\):\1:g" ${rootfs}/etc/locale.gen | ||
36 | LC_ALL=C chroot ${rootfs} /usr/sbin/locale-gen | ||
37 | elif [[ ! -z ${LANG} ]] | ||
38 | then | ||
39 | sed -i "s:^#\(${LANG}\):\1:g" ${rootfs}/etc/locale.gen | ||
40 | echo "LANG=${LANG}" > ${rootfs}/etc/env.d/01locale | ||
41 | LC_ALL=C chroot ${rootfs} /usr/sbin/locale-gen | ||
42 | LC_ALL=C chroot ${rootfs} /sbin/env-rebuild | ||
43 | elif [[ ! -z ${LC_ALL} ]] | ||
44 | then | ||
45 | sed -i "s:^#\(${LC_ALL}\):\1:g" ${rootfs}/etc/locale.gen | ||
46 | echo "LC_ALL=${LC_ALL}" > ${rootfs}/etc/env.d/01locale | ||
47 | LC_ALL=C chroot ${rootfs} /usr/sbin/locale-gen | ||
48 | LC_ALL=C chroot ${rootfs} /sbin/env-rebuild | ||
49 | fi | ||
50 | |||
51 | # configure the inittab | ||
52 | cat <<EOF > ${rootfs}/etc/inittab | ||
53 | id:3:initdefault: | ||
54 | si::sysinit:/etc/rc.d/init.d/rc sysinit | ||
55 | l0:0:wait:/etc/rc.d/init.d/rc 0 | ||
56 | l1:S1:wait:/etc/rc.d/init.d/rc 1 | ||
57 | l2:2:wait:/etc/rc.d/init.d/rc 2 | ||
58 | l3:3:wait:/etc/rc.d/init.d/rc 3 | ||
59 | l4:4:wait:/etc/rc.d/init.d/rc 4 | ||
60 | l5:5:wait:/etc/rc.d/init.d/rc 5 | ||
61 | l6:6:wait:/etc/rc.d/init.d/rc 6 | ||
62 | su:S016:once:/sbin/sulogin | ||
63 | 1:2345:respawn:/sbin/agetty console 38400 | ||
64 | 2:2345:respawn:/sbin/agetty tty2 38400 linux | ||
65 | 3:2345:respawn:/sbin/agetty tty3 38400 linux | ||
66 | 4:2345:respawn:/sbin/agetty tty4 38400 linux | ||
67 | 5:2345:respawn:/sbin/agetty tty5 38400 linux | ||
68 | 6:2345:respawn:/sbin/agetty tty6 38400 linux | ||
69 | x:a:once:/etc/X11/startxdm | ||
70 | EOF | ||
71 | |||
72 | # configure the network using dhcp | ||
73 | cat <<EOF > ${rootfs}/etc/conf.d/net.eth0 | ||
74 | ONBOOT="yes" | ||
75 | NETWORKING="dhcp" | ||
76 | EOF | ||
77 | |||
78 | # set the hostname | ||
79 | cat <<EOF > ${rootfs}/etc/hostname | ||
80 | ${hostname} | ||
81 | EOF | ||
82 | |||
83 | # remove /, /boot, swap from fstab (\s = space) | ||
84 | sed -i -e '/\s\/\s/d' -e '/\s\/boot\s/d' -e '/\sswap\s/d' ${rootfs}/etc/fstab | ||
85 | |||
86 | # remove pointless services in a container | ||
87 | chroot ${rootfs} /sbin/rc-config del checkfs | ||
88 | chroot ${rootfs} /sbin/rc-config del setclock | ||
89 | |||
90 | #echo "root:foobar" | chroot ${rootfs} chpasswd | ||
91 | chroot ${rootfs} usermod -p $(openssl passwd -1 foobar) root | ||
92 | echo "Root password is 'foobar', please change!" | ||
93 | |||
94 | # create missing device nodes | ||
95 | [[ ! -e ${rootfs}/dev/null ]] && mknod -m 666 ${rootfs}/dev/null c 1 3 | ||
96 | [[ ! -e ${rootfs}/dev/zero ]] && mknod -m 666 ${rootfs}/dev/zero c 1 5 | ||
97 | [[ ! -e ${rootfs}/dev/random ]] && mknod -m 666 ${rootfs}/dev/random c 1 8 | ||
98 | [[ ! -e ${rootfs}/dev/urandom ]] && mknod -m 666 ${rootfs}/dev/urandom c 1 9 | ||
99 | [[ ! -e ${rootfs}/dev/pts ]] && mkdir -m 755 ${rootfs}/dev/pts | ||
100 | [[ ! -e ${rootfs}/dev/shm ]] && mkdir -m 1777 ${rootfs}/dev/shm | ||
101 | [[ ! -e ${rootfs}/dev/tty ]] && mknod -m 666 ${rootfs}/dev/tty c 5 0 | ||
102 | [[ ! -e ${rootfs}/dev/console ]] && mknod -m 600 ${rootfs}/dev/console c 5 1 | ||
103 | [[ ! -e ${rootfs}/dev/tty0 ]] && mknod -m 666 ${rootfs}/dev/tty0 c 4 0 | ||
104 | [[ ! -e ${rootfs}/dev/tty1 ]] && mknod -m 666 ${rootfs}/dev/tty1 c 4 1 | ||
105 | [[ ! -e ${rootfs}/dev/tty2 ]] && mknod -m 666 ${rootfs}/dev/tty2 c 4 2 | ||
106 | [[ ! -e ${rootfs}/dev/tty3 ]] && mknod -m 666 ${rootfs}/dev/tty3 c 4 3 | ||
107 | [[ ! -e ${rootfs}/dev/tty4 ]] && mknod -m 666 ${rootfs}/dev/tty4 c 4 4 | ||
108 | [[ ! -e ${rootfs}/dev/tty5 ]] && mknod -m 666 ${rootfs}/dev/tty5 c 4 5 | ||
109 | [[ ! -e ${rootfs}/dev/tty6 ]] && mknod -m 666 ${rootfs}/dev/tty6 c 4 6 | ||
110 | [[ ! -e ${rootfs}/dev/full ]] && mknod -m 666 ${rootfs}/dev/full c 1 7 | ||
111 | [[ ! -e ${rootfs}/dev/initctl ]] && mknod -m 600 ${rootfs}/dev/initctl p | ||
112 | [[ ! -e ${rootfs}/dev/ptmx ]] && mknod -m 666 ${rootfs}/dev/ptmx c 5 2 | ||
113 | |||
114 | return 0 | ||
115 | } | ||
116 | |||
117 | download_magellan() | ||
118 | { | ||
119 | local cache="$1" | ||
120 | local arch="$2" | ||
121 | local distribution="unstable" | ||
122 | local mageprofile="$(basename $(readlink /etc/mage-profile))" | ||
123 | local extrapackages="dialog iproute2 openssh" | ||
124 | |||
125 | # check the mini magellan was not already downloaded | ||
126 | mkdir -p "${cache}/partial-${arch}" | ||
127 | if [ $? -ne 0 ] | ||
128 | then | ||
129 | echo "Failed to create '${cache}/partial-${arch}' directory" | ||
130 | return 1 | ||
131 | fi | ||
132 | |||
133 | # setup magerc | ||
134 | cat <<EOF > ${cache}/partial-${arch}/mage.rc.bootstrap | ||
135 | ARCH="${arch}" | ||
136 | MAGE_DISTRIBUTION="${distribution}" | ||
137 | |||
138 | MAGEDIR="/usr/mage" | ||
139 | PKGDIR="/var/cache/mage/packages" | ||
140 | BUILDDIR="/var/tmp/magebuild" | ||
141 | INSTALLDB="/var/db/mage" | ||
142 | VIRTUALDB_DEFAULTS="/etc/mage-profile/virtuals.defaults" | ||
143 | VIRTUALDB_FILE="\${INSTALLDB}/virtuals" | ||
144 | |||
145 | VERBOSE="off" | ||
146 | MAGEDEBUG="off" | ||
147 | |||
148 | MIRRORS="http://magellan-linux.de/magellan/magellan-dev/svn/\${MAGE_DISTRIBUTION}" | ||
149 | RSYNC="rsync://magellan-linux.de/mage-svn" | ||
150 | |||
151 | PACKAGES_SERVER_PATH="packages/\${ARCH}" | ||
152 | MAGE_UNINSTALL_TIMEOUT=0 | ||
153 | EOF | ||
154 | |||
155 | # download a mini magellan into a cache | ||
156 | echo "Downloading magellan minimal ..." | ||
157 | mage-bootstrap --profile ${mageprofile} --root ${cache}/partial-${arch} --magerc ${cache}/partial-${arch}/mage.rc.bootstrap --update-tarball | ||
158 | if [ $? -ne 0 ] | ||
159 | then | ||
160 | echo "Failed to download the rootfs, aborting." | ||
161 | return 1 | ||
162 | fi | ||
163 | |||
164 | # install extra packages | ||
165 | for pkg in ${extrapackages} | ||
166 | do | ||
167 | MROOT=${cache}/partial-${arch} mage install ${pkg} | ||
168 | if [ $? -ne 0 ] | ||
169 | then | ||
170 | echo "Failed to install package ${pkg}, aborting." | ||
171 | return 1 | ||
172 | fi | ||
173 | done | ||
174 | |||
175 | mv "${cache}/partial-${arch}" "${cache}/rootfs-${arch}" | ||
176 | echo "Download complete." | ||
177 | |||
178 | return 0 | ||
179 | } | ||
180 | |||
181 | copy_magellan() | ||
182 | { | ||
183 | local cache="$1" | ||
184 | local arch="$2" | ||
185 | local rootfs="$3" | ||
186 | |||
187 | # make a local copy of the minimagellan | ||
188 | echo "Copying rootfs to ${rootfs}..." | ||
189 | cp -a ${cache}/rootfs-${arch} ${rootfs} || return 1 | ||
190 | return 0 | ||
191 | } | ||
192 | |||
193 | install_magellan() | ||
194 | { | ||
195 | local cache="/var/cache/lxc/magellan" | ||
196 | local rootfs="$1" | ||
197 | |||
198 | mkdir -p /var/lock/subsys/ | ||
199 | ( | ||
200 | flock -n -x 200 | ||
201 | if [ $? -ne 0 ] | ||
202 | then | ||
203 | echo "Cache repository is busy." | ||
204 | return 1 | ||
205 | fi | ||
206 | |||
207 | arch=$(uname -m) | ||
208 | echo "Checking cache download in ${cache}/rootfs-${arch} ... " | ||
209 | if [ ! -e "${cache}/rootfs-${arch}" ] | ||
210 | then | ||
211 | download_magellan "${cache}" "${arch}" | ||
212 | if [ $? -ne 0 ] | ||
213 | then | ||
214 | echo "Failed to download 'magellan base'" | ||
215 | return 1 | ||
216 | fi | ||
217 | fi | ||
218 | |||
219 | install -d $(dirname ${rootfs}) | ||
220 | copy_magellan "${cache}" "${arch}" "${rootfs}" | ||
221 | if [ $? -ne 0 ]; then | ||
222 | echo "Failed to copy rootfs" | ||
223 | return 1 | ||
224 | fi | ||
225 | |||
226 | return 0 | ||
227 | |||
228 | ) 200>/var/lock/subsys/lxc | ||
229 | |||
230 | return $? | ||
231 | } | ||
232 | |||
233 | copy_configuration() | ||
234 | { | ||
235 | local path="$1" | ||
236 | local rootfs="$2" | ||
237 | local name="$3" | ||
238 | |||
239 | cat <<EOF >> ${path}/config | ||
240 | lxc.tty = 4 | ||
241 | lxc.pts = 1024 | ||
242 | lxc.rootfs = ${rootfs} | ||
243 | lxc.cgroup.devices.deny = a | ||
244 | # /dev/null and zero | ||
245 | lxc.cgroup.devices.allow = c 1:3 rwm | ||
246 | lxc.cgroup.devices.allow = c 1:5 rwm | ||
247 | # consoles | ||
248 | lxc.cgroup.devices.allow = c 5:1 rwm | ||
249 | lxc.cgroup.devices.allow = c 5:0 rwm | ||
250 | lxc.cgroup.devices.allow = c 4:0 rwm | ||
251 | lxc.cgroup.devices.allow = c 4:1 rwm | ||
252 | # /dev/{,u}random | ||
253 | lxc.cgroup.devices.allow = c 1:9 rwm | ||
254 | lxc.cgroup.devices.allow = c 1:8 rwm | ||
255 | lxc.cgroup.devices.allow = c 136:* rwm | ||
256 | lxc.cgroup.devices.allow = c 5:2 rwm | ||
257 | # rtc | ||
258 | lxc.cgroup.devices.allow = c 254:0 rwm | ||
259 | |||
260 | # mounts point | ||
261 | lxc.mount.entry=proc ${rootfs}/proc proc nodev,noexec,nosuid 0 0 | ||
262 | lxc.mount.entry=devpts ${rootfs}/dev/pts devpts defaults 0 0 | ||
263 | lxc.mount.entry=sysfs ${rootfs}/sys sysfs defaults 0 0 | ||
264 | EOF | ||
265 | |||
266 | if [ $? -ne 0 ] | ||
267 | then | ||
268 | echo "Failed to add configuration" | ||
269 | return 1 | ||
270 | fi | ||
271 | |||
272 | return 0 | ||
273 | } | ||
274 | |||
275 | clean() | ||
276 | { | ||
277 | local cache="/var/cache/lxc/magellan" | ||
278 | |||
279 | if [ ! -e ${cache} ] | ||
280 | then | ||
281 | exit 0 | ||
282 | fi | ||
283 | |||
284 | # lock, so we won't purge while someone is creating a repository | ||
285 | ( | ||
286 | flock -n -x 200 | ||
287 | if [ $? != 0 ]; then | ||
288 | echo "Cache repository is busy." | ||
289 | exit 1 | ||
290 | fi | ||
291 | |||
292 | echo -n "Purging the download cache..." | ||
293 | rm --preserve-root --one-file-system -rf ${cache} && echo "Done." || exit 1 | ||
294 | exit 0 | ||
295 | ) 200>/var/lock/subsys/lxc | ||
296 | } | ||
297 | |||
298 | usage() | ||
299 | { | ||
300 | cat <<EOF | ||
301 | $1 -h|--help -p|--path=<path> --clean | ||
302 | EOF | ||
303 | return 0 | ||
304 | } | ||
305 | |||
306 | options=$(getopt -o hp:n:c -l help,path:,name:,clean -- "$@") | ||
307 | if [ $? -ne 0 ] | ||
308 | then | ||
309 | usage $(basename $0) | ||
310 | exit 1 | ||
311 | fi | ||
312 | eval set -- "${options}" | ||
313 | |||
314 | while true | ||
315 | do | ||
316 | case "$1" in | ||
317 | -h|--help) usage $0 && exit 0;; | ||
318 | -p|--path) path=$2; shift 2;; | ||
319 | -n|--name) name=$2; shift 2;; | ||
320 | -c|--clean) clean=$2; shift 2;; | ||
321 | --) shift 1; break ;; | ||
322 | *) break ;; | ||
323 | esac | ||
324 | done | ||
325 | |||
326 | if [ ! -z "${clean}" -a -z "${path}" ] | ||
327 | then | ||
328 | clean || exit 1 | ||
329 | exit 0 | ||
330 | fi | ||
331 | |||
332 | # sanity checks | ||
333 | [ "$(id -u)" != "0" ] && die "This script should be run as 'root'" | ||
334 | type mage-bootstrap || die "'mage-bootstrap' command is missing" | ||
335 | [ -z "${path}" ] && die "'path' parameter is required" | ||
336 | |||
337 | rootfs=${path}/rootfs | ||
338 | |||
339 | install_magellan ${rootfs} || die "failed to install magellan" | ||
340 | configure_magellan ${rootfs} ${name} || die "failed to configure debian for a container" | ||
341 | copy_configuration ${path} ${rootfs} || die "failed write configuration file" | ||
342 | |||
343 | if [ ! -z ${clean} ] | ||
344 | then | ||
345 | clean || exit 1 | ||
346 | exit 0 | ||
347 | fi |