Modification : mk_{dir,reg} -> install .
[lhc/ateliers.git] / vm_hosted
index 925f1a9..0f900aa 100755 (executable)
--- a/vm_hosted
+++ b/vm_hosted
@@ -1,88 +1,66 @@
 #!/bin/sh
 set -e -f ${DRY_RUN:+-n} -u
 tool=${0%/*}
-. "$tool"/lib/functions.sh
+. "$tool"/lib/rule.sh
 . "$tool"/etc/vm.sh
-test "$(hostname --fqdn)" = "$vm_fqdn"
 
-rule_help () {
+rule_help () { # SYNTAX: [--hidden]
+       local hidden; [ ${1:+set} ] || hidden=set
        cat >&2 <<-EOF
-               DESCRIPTION: ce script regroupe des fonctions utilitaires
-                            pour gérer la VM _depuis_ la VM hébergée ;
-                            il sert à la fois d'outil et de documentation.
-                            Voir \`$tool/vm_host' pour les utilitaires côté machine hôte.
+               DESCRIPTION:
+                 ce script regroupe des règles pour administrer la VM ($vm_fqdn)
+                 _depuis_ la VM hébergée ($vm_fqdn) ;
+                 il sert à la fois d'outil (aisément bidouillable)
+                 et de documentation (préçise).
+                 Voir \`$tool/vm_host' pour les règles côté machine hôte ($vm_host).
                SYNTAX: $0 \$RULE \${RULE}_SYNTAX
                RULES:
-               $(sed -ne 's/^rule_\([^_][^ ]*\) () {\( *#.*\|\)/\t\1\2/p' "$tool"/vm.sh "$0")
+               $(sed -ne "s/^rule_\(${hidden:+[^_]}[^ ]*\) () {\( *#.*\|\)/  \1\2/p" "$tool"/etc/vm.sh "$0")
                ENVIRONMENT:
                  TRACE # affiche les commandes avant leur exécution
-               $(sed -ne 's/^readonly \([^ ][^ =]*\).*}\( *#.*\|\)$/\t$\1\2/p' "$tool"/vm.sh "$0")
+               $(sed -ne 's/^readonly \([^ ][^ =]*\).*}\( *#.*\|\)$/\t$\1\2/p' "$tool"/etc/vm.sh "$0")
                EOF
  }
 
+rule_git_config () {
+       (
+       cd "$tool"
+       git config --replace branch.master.remote .
+       git config --replace branch.master.merge refs/remotes/master
+       )
+ }
 rule_git_reset () {
        (
        cd "$tool"
-       git checkout -f -B master origin
+       git checkout -f -B master remotes/master
        git clean -f -d -x
        )
  }
 
-rule_chrooted () {
+rule_apt_get_install () { # SYNTAX: $package
+       case $(dpkg -s "$1" | grep '^Status: ') in
+               ("Status: install ok installed");;
+               (*)
+               test ! -x /usr/bin/etckeeper ||
+               assert 'sudo etckeeper unclean'
+               sudo apt-get "$@";;
+        esac
+ }
+
+rule__chrooted_configure () { # NOTE: est-ce bien utile à un moment ?
        export LANG=C
        export LC_CTYPE=C
        . /etc/profile
  }
 
-rule__etckeeper_init () {
-       mk_reg mod=644 own=root:root /etc/etckeeper/etckeeper.conf <<-EOF
-               VCS=git
-               GIT_COMMIT_OPTIONS=""
-               AVOID_DAILY_AUTOCOMMITS=1
-               #AVOID_SPECIAL_FILE_WARNING=1
-               #AVOID_COMMIT_BEFORE_INSTALL=1
-               HIGHLEVEL_PACKAGE_MANAGER=apt
-               LOWLEVEL_PACKAGE_MANAGER=dpkg
-               EOF
- }
-rule__locale_init () {
-       mk_reg mod=644 own=root:root /etc/locale.gen <<-EOF
-               fr_FR.UTF-8 UTF-8
-               EOF
-       sudo update-locale
- }
-rule__network_init () {
-       mk_reg mod= own= /etc/hostname <<-EOF
-               $vm
-               EOF
-       grep -q " $vm\$" /etc/hosts ||
-       mk_reg mod= own= --append /etc/hosts <<-EOF
-               127.0.0.1 $vm_fqdn $vm
-               EOF
-       mk_reg mod= own= /etc/network/interfaces <<-EOF
-               auto lo
-               iface lo inet loopback
-               
-               auto eth0=grenode
-               iface grenode inet static
-                   address   $vm_ipv4
-                   gateway   $vm_ipv4 # NOTE: proxy_arp sur la passerelle permet d'utiliser la même adresse
-                   network   $vm_ipv4
-                   broadcast $vm_ipv4
-                   netmask   255.255.255.255
-                   mtu 1300 # TODO: voir si c'est nécessaire à Lyon
-                   post-up   ip address add    $vm_ipv4/32 dev \$IFACE
-                   pre-down  ip address delete $vm_ipv4/32 dev \$IFACE
-               EOF
- }
-rule__apt_init () {
-       mk_reg mod= own= /etc/apt/sources.list <<-EOF
+rule_apt_configure () {
+       sudo install -m 660 -u root -g root /dev/stdin /etc/apt/sources.list <<-EOF
                deb http://ftp.fr.debian.org/debian $vm_lsb_name main contrib non-free
                EOF
-       mk_reg mod= own= /etc/apt/sources.list.d/$vm_lsb_name-backports.list <<-EOF
-               deb http://backports.debian.org/debian-backports $vm_lsb_name-backports main contrib non-free
+       sudo install -m 660 -u root -g root /dev/stdin /etc/apt/$vm_lsb_name-backports.list <<-EOF
+               #deb http://backports.debian.org/debian-backports $vm_lsb_name-backports main contrib non-free
                EOF
-       mk_reg mod= own= /etc/apt/preferences <<-EOF
+       sudo install -m 660 -u root -g root /dev/stdin /etc/apt/preferences <<-EOF
                Package: *
                Pin: release a=$vm_lsb_name
                Pin-Priority: 170
@@ -91,44 +69,162 @@ rule__apt_init () {
                Pin: release a=$vm_lsb_name-backports
                Pin-Priority: 200
                EOF
-       mk_reg mod= own= /etc/apt/sources.list.d/openerp.list <<-EOF
+       sudo install -m 660 -u root -g root /dev/stdin /etc/apt/sources.list.d/openerp.list <<-EOF
                deb http://nightly.openerp.com/trunk/nightly/deb/ ./
                EOF
  }
-rule__filesystem_init () {
-       mk_reg mod=644 own=root:root /etc/fstab <<-EOF
+rule_apticron_configure () {
+       rule apt_get_install apticron
+       sudo install -m 644 -u root -g root /dev/stdin /etc/apticron/apticron.conf <<-EOF
+               EMAIL="admin@$vm_domainname"
+               # DIFF_ONLY="1"
+               # LISTCHANGES_PROFILE="apticron"
+               # ALL_FQDNS="1"
+               # SYSTEM="foobar.example.com"
+               # IPADDRESSNUM="1"
+               # IPADDRESSES="192.0.2.1 2001:db8:1:2:3::1"
+               # NOTIFY_HOLDS="0"
+               # NOTIFY_NEW="0"
+               # NOTIFY_NO_UPDATES="0"
+               # CUSTOM_SUBJECT=""
+               # CUSTOM_NO_UPDATES_SUBJECT=""
+               # CUSTOM_FROM="root@$vm_fqdn"
+               EOF
+ }
+rule_boot_configure () {
+       warn "attention à n'installer GRUB sur AUCUN disque proposé !"
+       rule apt_get_install grub-pc
+       sudo install -d -m 644 -u root -g root /boot/grub
+       rule apt_get_install linux-image-$vm_arch
+       sudo install -m 644 -u root -g root /dev/stdin /etc/default/grub <<-EOF
+               GRUB_DEFAULT=0
+               GRUB_TIMEOUT=5
+               GRUB_DISTRIBUTOR=\`lsb_release -i -s 2> /dev/null || echo Debian\`
+               GRUB_CMDLINE_LINUX_DEFAULT="quiet"
+               GRUB_CMDLINE_LINUX="vt.default_utf8=1 rootfstype=ext4 loglevel=5 console=hvc0 ip=$vm_ipv4::$vm_ipv4:255.255.255.254:$vm:eth0:off resume=/dev/mapper/${vm}_swap_deciphered"
+               GRUB_DISABLE_RECOVERY="true"
+               #GRUB_PRELOAD_MODULES="lvm"
+               EOF
+       sudo install -m 644 -u root -g root /dev/stdin /boot/grub/device.map <<-EOF
+               (hd0)   /dev/xvda
+               (hd0)   /dev/mapper/domU-$(printf %s $vm_fqdn-disk | sed -e 's/-/--/g')
+               EOF
+       sudo update-grub2 # NOTE: prend en compte /boot/grub/device.map
+       rule initramfs_configure
+ }
+rule_etckeeper_configure () {
+       sudo install -m 644 -u root -g root /dev/stdin /etc/etckeeper/etckeeper.conf <<-EOF
+               VCS=git
+               GIT_COMMIT_OPTIONS=""
+               AVOID_DAILY_AUTOCOMMITS=1
+               #AVOID_SPECIAL_FILE_WARNING=1
+               AVOID_COMMIT_BEFORE_INSTALL=1
+               HIGHLEVEL_PACKAGE_MANAGER=apt
+               LOWLEVEL_PACKAGE_MANAGER=dpkg
+               EOF
+       rule apt_get_install etckeeper
+ }
+rule_filesystem_configure () {
+       sudo install -m 644 -u root -g root /dev/stdin /etc/fstab <<-EOF
                # <file system> <mount point> <type> <options> <dump> <pass>
                LABEL=${vm_lvm_lv}_boot /boot ext2 defaults 0 0
                proc /proc proc defaults 0 0
                sysfs /sys sysfs defaults 0 0
                tmpfs /tmp tmpfs rw,nosuid,nodev,auto,size=200m,nr_inodes=1000k,mode=1777,noatime,nodiratime 0 0
-               /dev/mapper/${vm_lvm_lv}_root_deciphered /     ext4 defaults,errors=remount-ro,acl,noatime 0 1
-               /dev/mapper/${vm_lvm_lv}_var_deciphered  /var  ext4 defaults,errors=remount-ro,acl,noatime 0 1
-               /dev/mapper/${vm_lvm_lv}_home_deciphered /home ext4 defaults,errors=remount-ro,acl,noatime,usrquota,grpquota 0 0
+               /dev/mapper/${vm_lvm_lv}_root_deciphered /     ext4 defaults,errors=remount-ro,acl,barrier=1,noatime 0 1
+               /dev/mapper/${vm_lvm_lv}_var_deciphered  /var  ext4 defaults,errors=remount-ro,acl,barrier=1,noatime 0 1
+               /dev/mapper/${vm_lvm_lv}_home_deciphered /home ext4 defaults,errors=remount-ro,acl,barrier=1,noatime,usrquota,grpquota 0 0
+               # NOTE: barrier=1 réduit drastiquement les performances d'écriture, mais garantit la cohérence du système de fichiers.
                /dev/mapper/${vm_lvm_lv}_swap_deciphered swap swap sw 0 0
                EOF
-       mk_reg mod=644 own=root:root /etc/crypttab <<-EOF
+       sudo install -m 644 -u root -g root /dev/stdin /etc/crypttab <<-EOF
                # <target name> <source device> <key file> <options>
                ${vm_lvm_lv}_root_deciphered /dev/$vm_lvm_vg/${vm_lvm_lv}_root none                         luks,lvm=$vm_lvm_vg
                ${vm_lvm_lv}_var_deciphered  /dev/$vm_lvm_vg/${vm_lvm_lv}_var  ${vm_lvm_lv}_root_deciphered luks,lvm=$vm_lvm_vg,keyscript=/lib/cryptsetup/scripts/decrypt_derived
                ${vm_lvm_lv}_home_deciphered /dev/$vm_lvm_vg/${vm_lvm_lv}_home ${vm_lvm_lv}_root_deciphered luks,lvm=$vm_lvm_vg,keyscript=/lib/cryptsetup/scripts/decrypt_derived
                ${vm_lvm_lv}_swap_deciphered /dev/$vm_lvm_vg/${vm_lvm_lv}_swap ${vm_lvm_lv}_root_deciphered luks,lvm=$vm_lvm_vg,keyscript=/lib/cryptsetup/scripts/decrypt_derived
                EOF
-       mk_reg mod=644 own=root:root /etc/sysctl.d/local-swap.conf <<-EOF
+       sudo install -m 644 -u root -g root /dev/stdin /etc/sysctl.d/local-swap.conf <<-EOF
                vm.swappiness = 10 # NOTE: n'utilise le swap qu'en cas d'absolue nécessité
                vm.vfs_cache_pressure=50
                EOF
  }
-rule__login_init () {
-       grep -q hvc0 /etc/securetty ||
-       mk_reg mod= own= --append /etc/securetty <<-EOF
+rule_initramfs_configure () {
+       sudo install -m 644 -u root -g root /dev/stdin /etc/initramfs-tools/initramfs.conf <<-EOF
+               MODULES=most
+               BUSYBOX=y
+               KEYMAP=y
+               COMPRESS=gzip
+               DEVICE=eth0
+               EOF
+       sudo install -m 644 -u root -g root /dev/stdin /etc/modprobe.d/xen-pv.conf <<-EOF
+               alias eth0 xennet
+               alias scsi_hostadapter xenblk
+               EOF
+       sudo install -m 644 -u root -g root /dev/stdin /etc/modules <<-EOF
+               sha1_generic
+               sha256_generic
+               sha512_generic
+               aes-x86_64
+               xts
+               # NOTE: pour Xen en mode HVM :
+               #modprobe xen-platform-pci
+               EOF
+       sudo install -m 644 -u root -g root /dev/stdin /etc/initramfs-tools/modules <<-EOF
+               EOF
+       sudo sed -e '/^configure_networking /s/ &$//' \
+        -i /usr/share/initramfs-tools/scripts/init-premount/dropbear
+        # NOTE: corrige une vermine : dropbear doit attendre que le réseau soit configuré..
+       ssh-keygen -F "init.$vm_fqdn" -f "$tool"/etc/openssh/known_hosts |
+       ( while IFS= read -r line
+        do case $line in (*" RSA") return 0; break;; esac
+        done; return 1 ) ||
+        {
+       sudo rm -f \
+        /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key \
+        /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key.pub
+       sudo dropbearkey -t rsa -s 4096 -f \
+        /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key
+        }
+       # NOTE: ne se préoccupe pas de dropbear_dss_host_key ; Debian la génère et l'utilise néamoins.
+       sudo install -d -m 640 -u root -g root \
+        /etc/initramfs-tools/root \
+        /etc/initramfs-tools/root/.ssh
+       getent group sudo |
+       while IFS=: read -r group x x users
+        do while test -n "$users" && IFS=, read -r user users <<-EOF
+                       $users
+                       EOF
+                do eval local home\; home="~$user"
+                       cat "$home"/etc/ssh/authorized_keys
+                done
+        done |
+       sudo install -m 644 -u root -g root /dev/stdin /etc/initramfs-tools/root/.ssh/authorized_keys
+       sudo rm -f \
+        /etc/initramfs-tools/root/.ssh/id_rsa.dropbear \
+        /etc/initramfs-tools/root/.ssh/id_rsa.pub \
+        /etc/initramfs-tools/root/.ssh/id_rsa
+        # NOTE: clefs générées par Debian
+       sudo update-initramfs -u
+ }
+rule_locale_configure () {
+       sudo install -m 644 -u root -g root /dev/stdin /etc/locale.gen <<-EOF
+               fr_FR.UTF-8 UTF-8
+               EOF
+       sudo update-locale
+ }
+rule_login_configure () {
+       grep -q '^hvc0$' /etc/securetty ||
+       sudo install -m 644 -u root -g root /dev/stdin /etc/securetty <<-EOF
+               $(cat /etc/securetty)
                hvc0
                EOF
-       grep -q xvc0 /etc/securetty ||
-       mk_reg mod= own= --append /etc/securetty <<-EOF
+       grep -q '^xvc0$' /etc/securetty ||
+       sudo install -m 644 -u root -g root /dev/stdin /etc/securetty <<-EOF
+               $(cat /etc/securetty)
                xvc0
                EOF
-       mk_reg mod=644 own=root:root /etc/inittab <<-EOF
+       sudo install -m 644 -u root -g root /dev/stdin /etc/inittab <<-EOF
                # /etc/inittab: init(8) configuration.
                
                # The default runlevel.
@@ -171,7 +267,7 @@ rule__login_init () {
                hvc:2345:respawn:/sbin/getty 38400 hvc0
                #xvc:2345:respawn:/sbin/getty 38400 xvc0
                EOF
-       mk_reg mod=644 own=root:root /etc/login.defs <<-EOF
+       sudo install -m 644 -u root -g root /dev/stdin /etc/login.defs <<-EOF
                MAIL_DIR         /var/mail
                FAILLOG_ENAB     yes
                LOG_UNKFAIL_ENAB no
@@ -183,17 +279,17 @@ rule__login_init () {
                HUSHLOGIN_FILE   .hushlogin
                ENV_SUPATH       PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
                ENV_PATH         PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
-               # NOTE: met les sbin/ dans ENV_PATH ;
-               #  - ça n'apporte aucune protection de ne pas les mettre ;
-               #  - ça frustre de ne pas les trouver.
+                # NOTE: met les sbin/ dans ENV_PATH ;
+                #  - ça n'apporte aucune protection de ne pas les mettre ;
+                #  - ça frustre de ne pas les trouver.
                TTYGROUP         tty
                TTYPERM          0600
                ERASECHAR        0177
                KILLCHAR         025
-               # NOTE: rwxrwx--- ;
-               #  - donne une même confiance au groupe propriétaire qu'au propriétaire ;
-               #  - facilite l'utilisation des ACL, qui sont dépendantes des droits du groupe propriétaire.
                UMASK            007
+                # NOTE: rwxrwx--- ;
+                #  - donne une même confiance au groupe propriétaire qu'au propriétaire ;
+                #  - facilite l'utilisation des ACL, qui sont dépendantes des droits du groupe propriétaire.
                PASS_MAX_DAYS    99999
                PASS_MIN_DAYS    0
                PASS_WARN_AGE    7
@@ -209,145 +305,64 @@ rule__login_init () {
                ENCRYPT_METHOD   SHA512
                EOF
        grep -q '^session optional pam_umask.so\>' /etc/pam.d/common-session ||
-       mk_reg mod= own= --append /etc/pam.d/common-session <<-EOF
+       sudo install -m 644 -u root -g root /dev/stdin /etc/pam.d/common-session <<-EOF
+               $(cat /etc/pam.d/common-session)
                session optional pam_umask.so
                EOF
  }
-rule__user_root_init () {
-       mk_dir mod=750 own=root:root /root/etc
-       mk_dir mod=750 own=root:root /root/etc/ssh
-       mk_dir mod=750 own=root:root /root/etc/gpg
-       mk_lnk etc/gpg /root/.gnupg
-       mk_lnk etc/ssh /root/.ssh
-       getent group sudo |
-       while IFS=: read -r group x x users
-        do while IFS=, read -r user
-                do eval local home\; home="~$user"
-                       cat "$home"/etc/ssh/authorized_keys
-                done <<-EOF
-                       $users
-                       EOF
-        done |
-       mk_reg mod=640 own=root:root /root/etc/ssh/authorized_keys
-       sudo find "$tool"/var/pub/openpgp -type f -name '*.key' -exec gpg --import {} \;
- }
-rule__initramfs_init () {
-       mk_reg mod=644 own=root:root /etc/initramfs-tools/initramfs.conf <<-EOF
-               MODULES=most
-               BUSYBOX=y
-               KEYMAP=y
-               COMPRESS=gzip
-               DEVICE=eth0
-               EOF
-       mk_reg mod=644 own=root:root /etc/modprobe.d/xen-pv.conf <<-EOF
-               alias eth0 xennet
-               alias scsi_hostadapter xenblk
-               EOF
-       mk_reg mod=644 own=root:root /etc/modules <<-EOF
-               sha1_generic
-               sha256_generic
-               sha512_generic
-               aes-x86_64
-               xts
-               # NOTE: pour Xen en mode HVM :
-               #modprobe xen-platform-pci
-               EOF
-       mk_reg mod=644 own=root:root /etc/initramfs-tools/modules <<-EOF
+rule_network_configure () {
+       sudo install -m 644 -u root -g root /dev/stdin /etc/hostname <<-EOF
+               $vm
                EOF
-       sudo sed -e '/^configure_networking /s/ &$//' \
-        -i /usr/share/initramfs-tools/scripts/init-premount/dropbear
-        # NOTE: corrige une vermine : dropbear doit attendre que le réseau soit configuré..
-       sudo rm -f \
-        /etc/initramfs-tools/etc/dropbear/dropbear_dss_host_key \
-        /etc/initramfs-tools/etc/dropbear/dropbear_dss_host_key.pub \
-        /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key \
-        /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key.pub
-       #mk_reg mod=640 own=root:root </dev/null \
-       # /etc/initramfs-tools/etc/dropbear/dropbear_dss_host_key \
-       # /etc/initramfs-tools/etc/dropbear/dropbear_dss_host_key.pub
-       ssh-keygen -F "init.$vm_fqdn" -f "$tool"/etc/openssh/known_hosts |
-       ( while IFS= read -r line
-        do case $line in (*" RSA") return 0; break;; esac
-        done; return 1 ) ||
-       sudo dropbearkey -t rsa -s 4096 -f \
-        /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key
-       ssh-keygen -F "init.$vm_fqdn" -f "$tool"/etc/openssh/known_hosts |
-       ( while IFS= read -r line
-        do case $line in (*" DSA") return 0; break;; esac
-        done; return 1 ) ||
-       sudo dropbearkey -t dss -s 1024 -f \
-        /etc/initramfs-tools/etc/dropbear/dropbear_dss_host_key
-       mk_dir mod=640 own=root:root \
-        /etc/initramfs-tools/root \
-        /etc/initramfs-tools/root/.ssh
-       getent group sudo |
-       while IFS=: read -r group x x users
-        do while IFS=, read -r user
-                do eval local home\; home="~$user"
-                       cat "$home"/etc/ssh/authorized_keys
-                done <<-EOF
-                       $users
-                       EOF
-        done |
-       mk_reg mod=644 own=root:root /etc/initramfs-tools/root/.ssh/authorized_keys
-       sudo rm -f \
-        /etc/initramfs-tools/root/.ssh/id_rsa.dropbear \
-        /etc/initramfs-tools/root/.ssh/id_rsa.pub \
-        /etc/initramfs-tools/root/.ssh/id_rsa
-        # NOTE: clefs générées par Debian
-       sudo update-initramfs -u
- }
-rule__boot_init () {
-       sudo apt-get install --reinstall grub-pc # XXX: attention à n'installer GRUB sur AUCUN disque proposé !
-       mk_dir mod=644 own=root:root /boot/grub
-       sudo apt-get install --reinstall linux-image-$vm_arch
-       mk_reg mod=644 own=root:root /etc/default/grub <<-EOF
-               GRUB_DEFAULT=0
-               GRUB_TIMEOUT=5
-               GRUB_DISTRIBUTOR=\`lsb_release -i -s 2> /dev/null || echo Debian\`
-               GRUB_CMDLINE_LINUX_DEFAULT="quiet"
-               GRUB_CMDLINE_LINUX="vt.default_utf8=1 rootfstype=ext4 loglevel=5 console=hvc0 ip=$vm_ipv4::$vm_ipv4:255.255.255.254:$vm:eth0:off resume=/dev/mapper/${vm}_swap_deciphered"
-               GRUB_DISABLE_RECOVERY="true"
-               #GRUB_PRELOAD_MODULES="lvm"
+       grep -q " $vm\$" /etc/hosts ||
+       sudo install -m 644 -u root -g root /dev/stdin /etc/hosts <<-EOF
+               $(cat /etc/hosts)
+               127.0.0.1 $vm_fqdn $vm
                EOF
-       mk_reg mod=644 own=root:root /boot/grub/device.map <<-EOF
-               (hd0)   /dev/xvda
-               (hd0)   /dev/mapper/domU-$(printf %s $vm_fqdn-disk | sed -e 's/-/--/g')
+       sudo install -m 644 -u root -g root /dev/stdin /etc/network/interfaces <<-EOF
+               auto lo
+               iface lo inet loopback
+               
+               auto eth0=grenode
+               iface grenode inet static
+                   address   $vm_ipv4
+                   gateway   $vm_ipv4 # NOTE: proxy_arp sur la passerelle permet d'utiliser la même adresse
+                   network   $vm_ipv4
+                   broadcast $vm_ipv4
+                   netmask   255.255.255.255
+                   mtu 1300
+                     # NOTE: il y a besoin de ça en l'état actuel du réseau de Grenode
+                     #       car la MTU des tunnels GRE/IPsec entre les routeurs de Grenode l'impose.
+                     #
+                     # root@ateliers:~# ping -M do -c 1 -s \$((1500-20-8-200)) soupirail.grenode.net
+                     # PING soupirail.grenode.net (91.216.110.1) 1272(1300) bytes of data.
+                     # 1280 bytes from soupirail.grenode.net (91.216.110.1): icmp_req=1 ttl=63 time=18.0 ms
+                     #
+                     # --- soupirail.grenode.net ping statistics ---
+                     # 1 packets transmitted, 1 received, 0% packet loss, time 0ms
+                     # rtt min/avg/max/mdev = 18.027/18.027/18.027/0.000 ms
+                     # root@ateliers:~# ping -M do -c 1 -s \$((1500-20-8-200+1)) soupirail.grenode.net
+                     # PING soupirail.grenode.net (91.216.110.1) 1273(1301) bytes of data.
+                     # From estran.grenode.net (91.216.110.6) icmp_seq=1 Frag needed and DF set (mtu = 1300)
+                     #
+                     # --- soupirail.grenode.net ping statistics ---
+                     # 0 packets transmitted, 0 received, +1 errors
+                   post-up   ip address add    $vm_ipv4/32 dev \$IFACE
+                   pre-down  ip address delete $vm_ipv4/32 dev \$IFACE
                EOF
-       sudo update-grub2 # NOTE: prend en compte /boot/grub/device.map
-       rule__initramfs_init
- }
-rule__bin_init () {
-       mk_lnk "$tool"/vm_hosted /usr/local/sbin/
- }
-rule_init () {
-       rule__etckeeper_init
-       rule__locale_init
-       rule__network_init
-       rule__apt_init
-       rule__filesystem_init
-       rule__login_init
-       rule__user_root_init
-       rule__boot_init
-       rule__bin_init
  }
-
-rule_disk_key_change () {
-       sudo cryptsetup luksChangeKey /dev/$vm_lvm_vg/${vm_lvm_lv}_root
- }
-
-rule_user_init () {
-       mk_dir mod=750 own="root:adm" /etc/skel/etc
-       mk_dir mod=770 own="root:adm" /etc/skel/etc/apache2
-       mk_dir mod=770 own="root:adm" /etc/skel/etc/ssh
-       mk_dir mod=700 own="root:adm" /etc/skel/var
-       mk_dir mod=700 own="root:adm" /etc/skel/var/log
-       mk_dir mod=700 own="root:adm" /etc/skel/var/cache
-       mk_dir mod=700 own="root:adm" /etc/skel/var/cache/ssh
-       mk_dir mod=700 own="root:adm" /etc/skel/tmp
-       mk_dir mod=700 own="root:adm" /etc/skel/tmp
-       mk_lnk etc/ssh                /etc/skel/.ssh
-       mk_lnk etc/gpg                /etc/skel/.gnupg
+rule_user_configure () {
+       sudo install -d -m 750 -u root -g adm \
+        /etc/skel/etc \
+        /etc/skel/etc/ssh
+       sudo install -d -m 770 -u root -g adm \
+        /etc/skel/etc/apache2 \
+        /etc/skel/var \
+        /etc/skel/var/log \
+        /etc/skel/var/cache \
+        /etc/skel/var/cache/ssh
+       sudo ln -fns etc/ssh /etc/skel/.ssh
+       sudo ln -fns etc/gpg /etc/skel/.gnupg
        ssh-keygen -F "$vm_fqdn" -f "$tool"/etc/openssh/known_hosts |
        ( while IFS= read -r line
         do case $line in (*" RSA") return 0; break;; esac
@@ -359,7 +374,7 @@ rule_user_init () {
         /etc/ssh/ssh_host_ecdsa_key \
         /etc/ssh/ssh_host_ecdsa_key.pub
         # NOTE: clefs générées par Debian
-       mk_reg mod=664 own=root:root  /etc/ssh/sshd_config <<-EOF
+       sudo install -m 644 -u root -g root /dev/stdin  /etc/ssh/sshd_config <<-EOF
                Port 22
                ListenAddress $vm_ipv4
                #ListenAddress ::
@@ -398,15 +413,15 @@ rule_user_init () {
                UsePAM yes
                EOF
        sudo service ssh restart
-       mk_reg mod=440 own=root:root /etc/sudoers.d/passwd-init <<-EOF
+       sudo install -m 640 -u root -g root /dev/stdin /etc/sudoers.d/passwd-init <<-EOF
                %sudo ALL=(ALL) NOPASSWD: /bin/sh -e -f -u -c \\
                  case \$(/usr/bin/passwd --status "\$SUDO_USER") in \\
                    ("\$SUDO_USER L "*) /usr/bin/passwd \$SUDO_USER;; esac
                EOF
-       mk_reg mod=440 own=root:root /etc/sudoers.d/etckeeper-unclean <<-EOF
+       sudo install -m 640 -u root -g root /dev/stdin /etc/sudoers.d/etckeeper-unclean <<-EOF
                %sudo ALL=(ALL) NOPASSWD: /usr/sbin/etckeeper unclean
                EOF
-       mk_reg mod=440 own=root:root /etc/sudoers.d/env_keep <<-EOF
+       sudo install -m 640 -u root -g root /dev/stdin /etc/sudoers.d/env_keep <<-EOF
                Defaults env_keep = " \\
                  EDITOR \\
                  GIT_AUTHOR_NAME \\
@@ -415,12 +430,59 @@ rule_user_init () {
                  GIT_COMMITTER_EMAIL \\
                 "
                EOF
-       mk_reg mod=555 own=root:root /usr/local/sbin/passwd-init <<-EOF
-               #!/bin/sh
+       sudo install -m 755 -u root -g root /dev/stdin /usr/local/sbin/passwd-init <<-EOF
+               #!/bin/sh -efu
+               # DESCRIPTION: permet à un-e utilisateurice d'initialiser ellui-même son mot-de-passe système.
                sudo /bin/sh -e -f -u -c \
                  'case \$(/usr/bin/passwd --status "\$SUDO_USER") in ("\$SUDO_USER L "*) /usr/bin/passwd \$SUDO_USER;; esac'
                EOF
  }
+rule_user_root_configure () {
+       sudo install -d -m 750 -u root -g adm \
+        /root/etc \
+        /root/etc/ssh \
+        /root/etc/gpg
+       sudo ln -fns etc/gpg /root/.gnupg
+       sudo ln -fns etc/ssh /root/.ssh
+       getent group sudo |
+       while IFS=: read -r group x x users
+        do while test -n "$users" && IFS=, read -r user users <<-EOF
+                       $users
+                       EOF
+                do eval local home\; home="~$user"
+                       cat "$home"/etc/ssh/authorized_keys
+                done
+        done |
+       sudo install -m 640 -u root -g root /dev/stdin /root/etc/ssh/authorized_keys
+       local key; local -; set +f
+       for key in "$tool"/var/pub/openpgp/*.key
+        do sudo gpg --import "$key"
+        done
+ }
+rule_bin_configure () {
+       sudo ln -fns "$tool"/vm_hosted /usr/local/sbin/
+ }
+rule_configure () {
+       rule etckeeper_configure
+       rule locale_configure
+       rule network_configure
+       rule apt_configure
+       rule filesystem_configure
+       rule login_configure
+       rule user_root_configure
+       rule boot_configure
+       rule apticron_configure
+       rule bin_configure
+ }
+
+rule_luks_key_change () {
+       sudo cryptsetup luksChangeKey /dev/$vm_lvm_vg/${vm_lvm_lv}_root
+ }
+
+rule_user_admin_configure () {
+       rule initramfs_configure
+       rule user_root_configure
+ }
 rule_user_admin_add () { # SYNTAX: $user
        local user=$1
        id "$user" >/dev/null ||
@@ -428,10 +490,14 @@ rule_user_admin_add () { # SYNTAX: $user
                # NOTE: le mot-de-passe doit être initialisé par l'utilisateur à l'aide de passwd-init .
        eval local home\; home="~$user"
        sudo adduser "$user" sudo
-       ssh_key_add user=$user "$tool"/var/pub/ssh/"$user".key "$home"/etc/ssh/authorized_keys
-       rule__initramfs_init
-       rule__user_root_init
-       sudo gpg --import "$tool"/var/pub/opengpg/"$user".key
+       sudo install -m 640 -u root -g root \
+        "$tool"/var/pub/ssh/"$user".key \
+        "$home"/etc/ssh/authorized_keys
+       local key; local -; set +f
+       for key in "$tool"/var/pub/openpgp/*.key
+        do sudo -u "$user" gpg --import "$key"
+        done
+       rule user_admin_configure
  }
 rule_user_mail_format () {
        mk_dir mod=770 own=root:adm /etc/skel/etc/procmail
@@ -794,11 +860,16 @@ rule_user_mail_format () {
        mk_reg mod=664 own=root:root /etc/postgrey/whitelist_recipients.local <<-EOF
                EOF
  }
-rule_mail_install () {
+rule_mail_configure () {
        sudo apt-get install postfix postgrey dovecot
  }
 
 rule=${1:-help}
 ${1+shift}
-set "${TRACE:+-x}"
-rule_$rule "$@"
+case $rule in
+ (help);;
+ (*)
+       assert 'test "$(hostname --fqdn)" = "$vm_fqdn"' vm_fqdn
+       ;;
+ esac
+rule $rule "$@"