2b4f26244d3066ae922a20102f7e4d2eaa4bf1b5
[sysadmin-cookbook] / recepies / lxc / lxc-debian
1 #!/bin/bash
2
3 #
4 # lxc: linux Container library
5
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
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 configure_debian()
24 {
25     rootfs=$1
26     hostname=$2
27
28     # configure the inittab
29     cat <<EOF > $rootfs/etc/inittab
30 id:3:initdefault:
31 si::sysinit:/etc/init.d/rcS
32 l0:0:wait:/etc/init.d/rc 0
33 l1:1:wait:/etc/init.d/rc 1
34 l2:2:wait:/etc/init.d/rc 2
35 l3:3:wait:/etc/init.d/rc 3
36 l4:4:wait:/etc/init.d/rc 4
37 l5:5:wait:/etc/init.d/rc 5
38 l6:6:wait:/etc/init.d/rc 6
39 # Normally not reached, but fallthrough in case of emergency.
40 z6:6:respawn:/sbin/sulogin
41 1:2345:respawn:/sbin/getty 38400 console
42 c1:12345:respawn:/sbin/getty 38400 tty1 linux
43 c2:12345:respawn:/sbin/getty 38400 tty2 linux
44 c3:12345:respawn:/sbin/getty 38400 tty3 linux
45 c4:12345:respawn:/sbin/getty 38400 tty4 linux
46 EOF
47
48     # disable selinux in debian
49     mkdir -p $rootfs/selinux
50     echo 0 > $rootfs/selinux/enforce
51
52     # by default setup root password with no password
53     cat <<EOF > $rootfs/etc/ssh/sshd_config
54 Port 22
55 Protocol 2
56 HostKey /etc/ssh/ssh_host_rsa_key
57 HostKey /etc/ssh/ssh_host_dsa_key
58 UsePrivilegeSeparation yes
59 KeyRegenerationInterval 3600
60 ServerKeyBits 768
61 SyslogFacility AUTH
62 LogLevel INFO
63 LoginGraceTime 120
64 PermitRootLogin yes
65 StrictModes yes
66 RSAAuthentication yes
67 PubkeyAuthentication yes
68 IgnoreRhosts yes
69 RhostsRSAAuthentication no
70 HostbasedAuthentication no
71 PermitEmptyPasswords yes
72 ChallengeResponseAuthentication no
73 EOF
74
75     # configure the network using the dhcp
76     cat <<EOF > $rootfs/etc/network/interfaces
77 auto lo
78 iface lo inet loopback
79
80 auto eth0
81 iface eth0 inet dhcp
82 EOF
83
84     # set the hostname
85     cat <<EOF > $rootfs/etc/hostname
86 $hostname
87 EOF
88
89     # reconfigure some services
90     chroot $rootfs /usr/sbin/dpkg-reconfigure locales
91
92     # remove pointless services in a container
93     chroot $rootfs /usr/sbin/update-rc.d -f umountfs remove
94     chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh remove
95     chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh remove
96 }
97
98 download_debian()
99 {
100     packages=\
101 ifupdown,\
102 locales,\
103 libui-dialog-perl,\
104 dialog,\
105 dhcp-client,\
106 netbase,\
107 net-tools,\
108 iproute,\
109 openssh-server
110
111     cache=$1
112     arch=$2
113
114     # check the mini debian was not already downloaded
115     mkdir -p "$cache/partial-$arch"
116     if [ $? -ne 0 ]; then
117         echo "Failed to create '$cache/partial-$arch' directory"
118         return 1
119     fi
120
121     # download a mini debian into a cache
122     echo "Downloading debian minimal ..."
123     debootstrap --verbose --variant=minbase --arch=$arch \
124         --include $packages \
125         lenny $cache/partial-$arch http://ftp.debian.org/debian
126     if [ $? -ne 0 ]; then
127         echo "Failed to download the rootfs, aborting."
128         return 1
129     fi
130
131     mv "$1/partial-$arch" "$1/rootfs-$arch"
132     echo "Download complete."
133
134     return 0
135 }
136
137 copy_debian()
138 {
139     cache=$1
140     arch=$2
141     rootfs=$3
142
143     # make a local copy of the minidebian
144     echo -n "Copying rootfs to $rootfs..."
145     cp -a $cache/rootfs-$arch $rootfs || return 1
146     return 0
147 }
148
149 install_debian()
150 {
151     cache="/var/cache/lxc/debian"
152     rootfs=$1
153     mkdir -p /var/lock/subsys/
154     (
155         flock -n -x 200
156         if [ $? -ne 0 ]; then
157             echo "Cache repository is busy."
158             return 1
159         fi
160
161         arch=$(arch)
162         if [ "$arch" == "x86_64" ]; then
163             arch=amd64
164         fi
165
166         if [ "$arch" == "i686" ]; then
167             arch=i386
168         fi
169
170         echo "Checking cache download in $cache/rootfs-$arch ... "
171         if [ ! -e "$cache/rootfs-$arch" ]; then
172             download_debian $cache $arch
173             if [ $? -ne 0 ]; then
174                 echo "Failed to download 'debian base'"
175                 return 1
176             fi
177         fi
178
179         copy_debian $cache $arch $rootfs
180         if [ $? -ne 0 ]; then
181             echo "Failed to copy rootfs"
182             return 1
183         fi
184
185         return 0
186
187         ) 200>/var/lock/subsys/lxc
188
189     return $?
190 }
191
192 copy_configuration()
193 {
194     path=$1
195     rootfs=$2
196     name=$3
197
198     cat <<EOF >> $path/config
199 lxc.tty = 4
200 lxc.pts = 1024
201 lxc.rootfs = $rootfs
202 lxc.cgroup.devices.deny = a
203 # /dev/null and zero
204 lxc.cgroup.devices.allow = c 1:3 rwm
205 lxc.cgroup.devices.allow = c 1:5 rwm
206 # consoles
207 lxc.cgroup.devices.allow = c 5:1 rwm
208 lxc.cgroup.devices.allow = c 5:0 rwm
209 lxc.cgroup.devices.allow = c 4:0 rwm
210 lxc.cgroup.devices.allow = c 4:1 rwm
211 # /dev/{,u}random
212 lxc.cgroup.devices.allow = c 1:9 rwm
213 lxc.cgroup.devices.allow = c 1:8 rwm
214 lxc.cgroup.devices.allow = c 136:* rwm
215 lxc.cgroup.devices.allow = c 5:2 rwm
216 # rtc
217 lxc.cgroup.devices.allow = c 254:0 rwm
218 EOF
219
220     if [ $? -ne 0 ]; then
221         echo "Failed to add configuration"
222         return 1
223     fi
224
225     return 0
226 }
227
228 clean()
229 {
230     cache="/var/cache/lxc/debian"
231
232     if [ ! -e $cache ]; then
233         exit 0
234     fi
235
236     # lock, so we won't purge while someone is creating a repository
237     (
238         flock -n -x 200 
239         if [ $? != 0 ]; then
240             echo "Cache repository is busy."
241             exit 1
242         fi
243
244         echo -n "Purging the download cache..."
245         rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
246         exit 0
247
248     ) 200>/var/lock/subsys/lxc
249 }
250
251 usage()
252 {
253     cat <<EOF
254 $1 -h|--help -p|--path=<path> --clean
255 EOF
256     return 0
257 }
258
259 options=$(getopt -o hp:n:c -l help,path:,name:,clean -- "$@")
260 if [ $? -ne 0 ]; then
261         usage $(basename $0)
262         exit 1
263 fi
264 eval set -- "$options"
265
266 while true
267 do
268     case "$1" in
269         -h|--help)      usage $0 && exit 0;;
270         -p|--path)      path=$2; shift 2;;
271         -n|--name)      name=$2; shift 2;;
272         -c|--clean)     clean=$2; shift 2;;
273         --)             shift 1; break ;;
274         *)              break ;;
275     esac
276 done
277
278 if [ ! -z "$clean" -a -z "$path" ]; then
279     clean || exit 1
280     exit 0
281 fi
282
283 type debootstrap
284 if [ $? -ne 0 ]; then
285     echo "'debootstrap' command is missing"
286     exit 1
287 fi
288
289 if [ -z "$path" ]; then
290     echo "'path' parameter is required"
291     exit 1
292 fi
293
294 if [ "$(id -u)" != "0" ]; then
295     echo "This script should be run as 'root'"
296     exit 1
297 fi 
298
299 rootfs=$path/rootfs
300
301 install_debian $rootfs
302 if [ $? -ne 0 ]; then
303     echo "failed to install debian"
304     exit 1
305 fi
306
307 configure_debian $rootfs $name
308 if [ $? -ne 0 ]; then
309     echo "failed to configure debian for a container"
310     exit 1
311 fi
312
313 copy_configuration $path $rootfs
314 if [ $? -ne 0 ]; then
315     echo "failed write configuration file"
316     exit 1
317 fi
318
319 if [ ! -z $clean ]; then
320     clean || exit 1
321     exit 0
322 fi