Contents of /trunk/lxc/lxc-magellan.sh
Parent Directory | Revision Log
Revision 1057 -
(show 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 | #!/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 |