8bbe166029906fff3faac667da21ee523ac8756d
[lhc/ateliers.git] / vm_host
1 #!/bin/sh
2 set -e -f ${DRY_RUN:+-n} -u
3 tool=${0%/*}
4 . "$tool"/lib/rule.sh
5 . "$tool"/etc/vm.sh
6 export TRACE=1
7
8 rule_help () { # SYNTAX: [--hidden]
9 local hidden; [ ${1:+set} ] || hidden=set
10 cat >&2 <<-EOF
11 DESCRIPTION:
12 ce script regroupe des règles pour administrer la VM ($vm_fqdn)
13 _depuis_ son hôte ($vm_host) ;
14 il sert à la fois d'outil (aisément bidouillable)
15 et de documentation (préçise).
16 Voir \`$tool/vm_hosted' pour les règles côté VM hébergée.
17 SYNTAX: $0 \$RULE \${RULE}_SYNTAX
18 RULES:
19 $(sed -ne "s/^rule_\(${hidden:+[^_]}[^ ]*\) () {\( *#.*\|\)/ \1\2/p" "$tool"/etc/vm.sh "$0")
20 ENVIRONMENT:
21 TRACE # affiche les commandes avant leur exécution
22 $(sed -ne 's/^readonly \([^ ][^ =]*\).*}\( *#.*\|\)$/\t$\1\2/p' "$tool"/etc/vm.sh "$0")
23 EOF
24 }
25
26 readonly vm_dev_disk=/dev/mapper/domU-$(printf %s "$vm_fqdn-disk" | sed -e 's/-/--/g')
27 readonly vm_dev_disk_boot="${vm_dev_disk}1"
28
29 rule_git_configure () {
30 (
31 cd "$tool"
32 git config --replace branch.master.remote .
33 git config --replace branch.master.merge refs/remotes/master
34 local tool
35 tool=$(cd "$tool"; cd -)
36 install -m 770 /dev/stdin .git/hooks/post-update <<-EOF
37 #!/bin/sh -efux
38 case \$1 in
39 (refs/remotes/master)
40 cd ..
41 #git --git-dir=\$PWD/.git checkout -f -B master remotes/master &&
42 git --git-dir=\$PWD/.git checkout HEAD'^' &&
43 git --git-dir=\$PWD/.git branch -f master remotes/master &&
44 git --git-dir=\$PWD/.git checkout master
45 git --git-dir=\$PWD/.git clean -f -d -x
46 ;;
47 esac
48 EOF
49 )
50 }
51
52 rule_vm_configure () {
53 sudo install -m 644 -u root -g root /dev/stdin /etc/xen/$vm_fqdn.cfg <<-EOF
54 # -*- mode: python; -*-
55 # DOC: http://wiki.xen.org/wiki/Xen_Linux_PV_on_HVM_drivers
56 import os, re
57 name = "$vm_fqdn"
58 arch = os.uname()[4]
59 memory = 2048
60 vcpus = 1
61 pae = 1
62 acpi = 1
63 apic = 1
64 vif = ['mac=$vm_mac,bridge=$vm_bridge']
65 disk = ['phy:/dev/domU/$vm_fqdn-disk,hda,w']
66 device_model = 'qemu-dm'
67 # HVM :
68 #kernel = "/usr/lib/xen-4.0/boot/hvmloader"
69 #builder = 'hvm'
70 #xen_platform_pci = 1 # NOTE: the guest VM can use optimized PV on HVM drivers
71 # PV :
72 #kernel = "pv-grub.gz" # NOTE: pas encore dans Debian car il ne fonctionne qu'avec grub-legacy
73 #extra = "(hd0,0)/grub/grub.cfg"
74 bootloader = '/usr/bin/pygrub'
75
76 # boot on floppy (a), hard disk (c) or CD-ROM (d)
77 #boot = 'd'
78
79 #vnc = 1
80 #sdl = 0
81 #vncconsole = 0
82 #vnclisten = "0.0.0.0"
83 #vncpasswd = ""
84 #usbdevice = 'tablet'
85
86 keymap = 'fr'
87 serial = 'pty'
88 on_poweroff = 'destroy'
89 on_reboot = 'restart'
90 on_crash = 'restart'
91 EOF
92 }
93 rule_vm_start () {
94 test ! -e /dev/domU/$vm_fqdn-disk1
95 sudo xm create $vm_fqdn.cfg
96 rule vm_attach
97 }
98 rule_vm_attach () {
99 assert '! pgrep -f "sudo xm console $vm_fqdn"'
100 info 'Ctrl-] pour se détacher de la console'
101 sudo xm console $vm_fqdn
102 }
103 rule_vm_stop () {
104 sudo xm shutdown $vm_fqdn
105 }
106 rule_vm_stop_force () {
107 sudo xm destroy $vm_fqdn
108 }
109
110 rule_disk_mount () { # DESCRIPTION: montage du disque de la VM depuis l'hôte
111 sudo kpartx -a -v /dev/domU/$vm_fqdn-disk
112 #sudo xm block-attach 0 phy:/dev/domU/$vm_fqdn-disk $vm_dev_disk w
113 }
114 rule_disk_umount () { # DESCRIPTION: démontage du disque de la VM depuis l'hôte
115 rule part_boot_umount
116 case $vm_use_lvm in
117 (yes)
118 rule part_lvm_umount
119 ;;
120 (no)
121 rule part_root_umount
122 rule part_var_umount
123 rule part_home_umount
124 ;;
125 (*) exit 1;;
126 esac
127 sudo kpartx -d -v /dev/domU/$vm_fqdn-disk
128 #sudo xm block-detach 0 $vm_dev_disk
129 # XXX: DANGEREUX ; si jamais il bloque parce que le disque était encore utilisé :
130 # utiliser xm block-detach 0 $vm_dev_disk --force ;
131 # ôter les éventuels mappages LVM concernés avec dmsetup table et dmsetup remove --force ;
132 # ôter les mappages concernés dans /etc/lvm/cache/.cache,
133 # et pour bien trouver tous les mappages :
134 # % sudo find /dev -type l -exec sh -c 'printf "%s -> " "$@"; readlink "$@"' - {} \; | grep $vm_dev_disk
135 # enfin, ôter l'éventuel verrou dans /var/lock/lvm/
136 }
137
138 case $vm_use_lvm in
139 (no)
140 readonly vm_dev_disk_swap="${vm_dev_disk}5"
141 readonly vm_dev_disk_root="${vm_dev_disk}6"
142 readonly vm_dev_disk_var="${vm_dev_disk}7"
143 readonly vm_dev_disk_home="${vm_dev_disk}8"
144 ;;
145 (yes)
146 readonly vm_lvm_pv="${vm_dev_disk}2"
147 readonly vm_dev_disk_swap=/dev/$vm_lvm_vg/${vm_lvm_lv}_swap
148 readonly vm_dev_disk_root=/dev/$vm_lvm_vg/${vm_lvm_lv}_root
149 readonly vm_dev_disk_var=/dev/$vm_lvm_vg/${vm_lvm_lv}_var
150 readonly vm_dev_disk_home=/dev/$vm_lvm_vg/${vm_lvm_lv}_home
151 ;;
152 (*) exit 1;;
153 esac
154
155 rule_disk_format () { # DESCRIPTION: partitionnage du disque de la VM
156 case $vm_use_lvm in
157 (no)
158 sudo sfdisk $vm_dev_disk <<-EOF
159 # partition table of $vm_dev_disk
160 unit: sectors
161
162 ${vm_dev_disk}1 : start= 63, size= 497952, Id=83, bootable
163 ${vm_dev_disk}2 : start= 498015, size=418927005, Id= 5
164 ${vm_dev_disk}3 : start= 0, size= 0, Id= 0
165 ${vm_dev_disk}4 : start= 0, size= 0, Id= 0
166 ${vm_dev_disk}5 : start= 498078, size= 1959867, Id=82
167 ${vm_dev_disk}6 : start= 2458008, size= 29302497, Id=83
168 ${vm_dev_disk}7 : start= 31760568, size= 9767457, Id=83
169 ${vm_dev_disk}8 : start= 41528088, size=377896932, Id=83
170 EOF
171 ;;
172 (yes)
173 sudo sfdisk $vm_dev_disk <<-EOF
174 # partition table of $vm_dev_disk
175 unit: sectors
176
177 ${vm_dev_disk}1 : start= 63, size= 497952, Id=83, bootable
178 ${vm_dev_disk}2 : start= 498015, size=418927005, Id=8E
179 EOF
180 ;;
181 (*) exit 1;;
182 esac
183 #sudo partprobe $vm_dev_disk
184 sudo kpartx -u -v /dev/domU/$vm_fqdn-disk
185 }
186
187 rule_part_lvm_format () {
188 rule part_lvm_umount
189 ! sudo vgs | grep -q "^ $vm_lvm_vg " ||
190 sudo vgremove $vm_lvm_vg
191 sudo pvcreate --dataalignment 512k $vm_lvm_pv
192 sudo vgcreate --dataalignment 512k $vm_lvm_vg $vm_lvm_pv
193 sudo lvcreate --contiguous y -n ${vm_lvm_lv}_swap -L 1G $vm_lvm_vg
194 sudo lvcreate --contiguous y -n ${vm_lvm_lv}_root -L 15G $vm_lvm_vg
195 sudo lvcreate --contiguous y -n ${vm_lvm_lv}_var -L 5G $vm_lvm_vg
196 sudo lvcreate --contiguous y -n ${vm_lvm_lv}_home -l 99%FREE $vm_lvm_vg
197 rule part_lvm_umount
198 }
199 rule_part_lvm_mount () {
200 case $vm_use_lvm in
201 (yes)
202 sudo vgchange -a y $vm_lvm_vg
203 ;;
204 (*) exit 1;;
205 esac
206 }
207 rule_part_lvm_umount () {
208 case $vm_use_lvm in
209 (yes)
210 rule part_root_umount
211 rule part_var_umount
212 rule part_home_umount
213 ! sudo vgs | grep -q "^ $vm_lvm_vg " ||
214 sudo vgchange -a n $vm_lvm_vg
215 ;;
216 (*) exit 1;;
217 esac
218 }
219
220 rule_part_randomize () { # SYNTAX: $part # NOTE: à anticiper
221 local part="$1"
222 eval "sudo dd if=/dev/urandom of=\$vm_dev_disk_$part"
223 }
224 rule_part_randomize_stat () { # SYNTAX: $part # DESCRIPTION: fait afficher la progression de rule_part_randomize
225 local part="$1"
226 eval "pkill -USR1 -f \"^dd if=/dev/urandom of=\$vm_dev_disk_$part\""
227 }
228 rule__part_encrypted_format () { # SYNTAX: $part # DESCRIPTION: formatage d'une partition distincte de /
229 # NOTE: la clef de chiffrement est dérivée de celle de /,
230 # / doit être déchiffrée pour que cela fonctionne.
231 local part="$1"
232 eval "local dev=\"\$vm_dev_disk_$part\""
233 test ! -e /dev/mapper/${vm_lvm_lv}_root_deciphered ||
234 sudo /bin/sh -c "/lib/cryptsetup/scripts/decrypt_derived ${vm_lvm_lv}_root_deciphered |
235 cryptsetup luksFormat --hash=sha512 --key-size=512 \
236 --cipher=aes-xts-essiv:sha256 --key-file=- --align-payload=8 $dev"
237 }
238 rule__part_encrypted_mount () { # SYNTAX: $part
239 local part="$1"
240 eval "local dev=\"\$vm_dev_disk_$part\""
241 test -e /dev/mapper/${vm_lvm_lv}_${part}_deciphered ||
242 sudo /bin/sh -c "/lib/cryptsetup/scripts/decrypt_derived ${vm_lvm_lv}_root_deciphered |
243 cryptsetup luksOpen --key-file=- $dev ${vm_lvm_lv}_${part}_deciphered"
244 }
245 rule__part_encrypted_umount () { # SYNTAX: $part
246 local part="$1"
247 eval "local dev=\"\$vm_dev_disk_$part\""
248 test ! -e /dev/mapper/${vm_lvm_lv}_${part}_deciphered ||
249 sudo cryptsetup luksClose ${vm_lvm_lv}_${part}_deciphered
250 }
251
252 rule_part_root_format () {
253 if ! mount | grep -q "^$vm_dev_disk_root "
254 then
255 sudo cryptsetup luksFormat --hash=sha512 --key-size=512 \
256 --cipher=aes-xts-essiv:sha256 --align-payload=8 $vm_dev_disk_root
257 sudo cryptsetup luksOpen $vm_dev_disk_root ${vm_lvm_lv}_root_deciphered
258 sudo mke2fs -t ext4 -c -c -m 5 -T ext4 -b $vm_e2fs_block_size \
259 -E resize=30G${vm_e2fs_extended_options} \
260 -L ${vm_lvm_lv}_root \
261 /dev/mapper/${vm_lvm_lv}_root_deciphered
262 ! mountpoint -q /mnt/$vm_fqdn
263 sudo mount -v /dev/mapper/${vm_lvm_lv}_root_deciphered /mnt/$vm_fqdn
264 sudo install -d -m 770 -o root -g root \
265 /mnt/$vm_fqdn/boot \
266 /mnt/$vm_fqdn/dev \
267 /mnt/$vm_fqdn/home \
268 /mnt/$vm_fqdn/proc \
269 /mnt/$vm_fqdn/root \
270 /mnt/$vm_fqdn/root/src \
271 /mnt/$vm_fqdn/root/src/$vm \
272 /mnt/$vm_fqdn/sys \
273 /mnt/$vm_fqdn/var
274 sudo umount -v /mnt/$vm_fqdn
275 sudo cryptsetup luksClose ${vm_lvm_lv}_root_deciphered
276 fi
277 }
278 rule_part_root_mount () {
279 test -e /dev/mapper/${vm_lvm_lv}_root_deciphered ||
280 sudo cryptsetup luksOpen $vm_dev_disk_root ${vm_lvm_lv}_root_deciphered
281 mountpoint -q /mnt/$vm_fqdn ||
282 sudo mount -v -t ext4 /dev/mapper/${vm_lvm_lv}_root_deciphered /mnt/$vm_fqdn
283 }
284 rule_part_root_umount () {
285 ! mountpoint -q /mnt/$vm_fqdn ||
286 sudo umount -v /mnt/$vm_fqdn
287 ! test -e /dev/mapper/${vm_lvm_lv}_root_deciphered ||
288 sudo cryptsetup luksClose ${vm_lvm_lv}_root_deciphered
289 }
290 rule_part_swap_format () {
291 rule _part_encrypted_format swap
292 rule _part_encrypted_mount swap
293 sudo mkswap -f -L ${vm_lvm_lv}_swap \
294 /dev/mapper/${vm_lvm_lv}_swap_deciphered
295 rule _part_encrypted_umount swap
296 }
297 rule_part_boot_format () {
298 mount | grep -q "^$vm_dev_disk_boot " ||
299 sudo mke2fs -t ext2 -c -c -m 5 -T small \
300 -E resize=1G${vm_e2fs_extended_options} \
301 -L ${vm_lvm_lv}_boot $vm_dev_disk_boot
302 }
303 rule_part_boot_mount () {
304 mountpoint -q /mnt/$vm_fqdn
305 test -d /mnt/$vm_fqdn/boot
306 mountpoint -q /mnt/$vm_fqdn/boot ||
307 sudo mount -v -t ext2 $vm_dev_disk_boot /mnt/$vm_fqdn/boot
308 }
309 rule_part_boot_umount () {
310 ! mountpoint -q /mnt/$vm_fqdn/boot ||
311 sudo umount -v /mnt/$vm_fqdn/boot
312 }
313 rule_part_var_format () {
314 rule _part_encrypted_format var
315 rule _part_encrypted_mount var
316 sudo mke2fs -t ext4 -c -c -m 5 -T ext4 -b $vm_e2fs_block_size \
317 -E resize=10G${vm_e2fs_extended_options} \
318 -L ${vm_lvm_lv}_var \
319 /dev/mapper/${vm_lvm_lv}_var_deciphered
320 rule _part_encrypted_umount var
321 }
322 rule_part_var_mount () {
323 rule _part_encrypted_mount var
324 mountpoint -q /mnt/$vm_fqdn/var ||
325 sudo mount -v -t ext4 /dev/mapper/${vm_lvm_lv}_var_deciphered /mnt/$vm_fqdn/var
326 }
327 rule_part_var_umount () {
328 ! mountpoint -q /mnt/$vm_fqdn/var ||
329 sudo umount -v /mnt/$vm_fqdn/var
330 rule _part_encrypted_umount var
331 }
332 rule_part_home_format () {
333 rule _part_encrypted_format home
334 rule _part_encrypted_mount home
335 sudo mke2fs -t ext4 -c -c -m 0 -T ext4 -b $vm_e2fs_block_size \
336 -E resize=400G${vm_e2fs_extended_options} \
337 -L ${vm_lvm_lv}_home \
338 /dev/mapper/${vm_lvm_lv}_home_deciphered
339 # NOTE: -O quota pas supporté par e2fsprogs/squeeze
340 rule _part_encrypted_umount home
341 }
342 rule_part_home_mount () {
343 rule _part_encrypted_mount home
344 mountpoint -q /mnt/$vm_fqdn/home ||
345 sudo mount -v -t ext4 /dev/mapper/${vm_lvm_lv}_home_deciphered /mnt/$vm_fqdn/home
346 }
347 rule_part_home_umount () {
348 ! mountpoint -q /mnt/$vm_fqdn/home ||
349 sudo umount -v /mnt/$vm_fqdn/home
350 rule _part_encrypted_umount home
351 }
352
353 rule_debian_install () {
354 rule disk_mount
355 rule part_lvm_mount
356 rule part_root_mount
357 rule part_boot_mount
358 rule part_var_mount
359 sudo DEBOOTSTRAP_DIR=/usr/share/debootstrap/ LANG=C LC_CTYPE=C debootstrap \
360 --arch=$vm_arch --verbose --keyring=/usr/share/keyrings/debian-archive-keyring.gpg \
361 --exclude=vim-tiny \
362 --include=$(printf '%s,' \
363 acl \
364 bsdmainutils \
365 busybox \
366 ca-certificates \
367 console-setup \
368 cryptsetup \
369 dash \
370 dnsutils \
371 dropbear \
372 etckeeper \
373 git-core \
374 gnupg \
375 hashalot \
376 htop \
377 ifupdown \
378 initramfs-tools \
379 kbd \
380 less \
381 locales \
382 lvm2 \
383 m4 \
384 mosh \
385 molly-guard \
386 ncurses-term \
387 openssh-client \
388 openssh-server \
389 openssl \
390 pciutils \
391 procps \
392 quota \
393 quotatool \
394 rsync \
395 screen \
396 sudo \
397 sysprofile \
398 vim-nox \
399 wget \
400 zsh \
401 ) \
402 $vm_lsb_name /mnt/$vm_fqdn/ \
403 http://ftp.fr.debian.org/debian/
404 rule part_var_umount
405 rule part_boot_umount
406 rule part_root_umount
407 }
408
409 rule_chroot () {
410 rule disk_mount
411 rule part_lvm_mount
412 rule part_root_mount
413 rule part_boot_mount
414 rule part_var_mount
415 #rule_part_home_mount
416 mountpoint -q /mnt/$vm_fqdn/proc ||
417 sudo mount -t proc proc /mnt/$vm_fqdn/proc
418 mountpoint -q /mnt/$vm_fqdn/sys ||
419 sudo mount -t sysfs sys /mnt/$vm_fqdn/sys
420 mountpoint -q /mnt/$vm_fqdn/dev ||
421 sudo mount --bind /dev /mnt/$vm_fqdn/dev
422 if test -d /mnt/$vm_fqdn/root/src/vm/.git
423 then
424 mountpoint -q /mnt/$vm_fqdn/root/src/vm ||
425 sudo mount --bind "$tool" /mnt/$vm_fqdn/root/src/vm
426 else
427 sudo rsync -a "$tool"/ /mnt/$vm_fqdn/root/src/vm
428 fi
429 sudo chroot /mnt/$vm_fqdn /bin/bash || true
430 rule _chroot_clean
431 }
432 rule__chroot_clean () {
433 ! sudo mountpoint -q /mnt/$vm_fqdn/root/src/vm ||
434 sudo umount -v /mnt/$vm_fqdn/root/src/vm
435 ! mountpoint -q /mnt/$vm_fqdn/dev ||
436 sudo umount -v /mnt/$vm_fqdn/dev
437 ! mountpoint -q /mnt/$vm_fqdn/sys ||
438 sudo umount -v /mnt/$vm_fqdn/sys
439 ! mountpoint -q /mnt/$vm_fqdn/proc ||
440 sudo umount -v /mnt/$vm_fqdn/proc
441 rule part_home_umount
442 rule part_var_umount
443 rule part_boot_umount
444 rule part_root_umount
445 rule disk_umount
446 }
447
448 rule=${1:-help}
449 ${1+shift}
450 case $rule in
451 (help);;
452 (*)
453 assert 'test "$(hostname --fqdn)" = "$vm_host"' vm_host
454 ;;
455 esac
456 rule $rule "$@"