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