#!/bin/sh
set -e -f ${DRY_RUN:+-n} -u
tool=${0%/*}
-. "$tool"/lib/functions.sh
+. "$tool"/lib/rule.sh
. "$tool"/etc/vm.sh
-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"/etc/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"/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_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
+ 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
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_apticron_init () {
- sudo apt-get install --reinstall apticron
- mk_reg mod=644 own=root:root /etc/default/grub <<-EOF
- EMAIL="admin@heureux-cyclage.org"
+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"
# NOTIFY_NO_UPDATES="0"
# CUSTOM_SUBJECT=""
# CUSTOM_NO_UPDATES_SUBJECT=""
- # CUSTOM_FROM="root@ateliers.heureux-cyclage.org"
+ # CUSTOM_FROM="root@$vm_fqdn"
EOF
- sudo service apticron restart
}
-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
+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_DISABLE_RECOVERY="true"
#GRUB_PRELOAD_MODULES="lvm"
EOF
- mk_reg mod=644 own=root:root /boot/grub/device.map <<-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_init
+ rule initramfs_configure
}
-rule_etckeeper_init () {
- mk_reg mod=644 own=root:root /etc/etckeeper/etckeeper.conf <<-EOF
+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
HIGHLEVEL_PACKAGE_MANAGER=apt
LOWLEVEL_PACKAGE_MANAGER=dpkg
EOF
+ rule apt_get_install etckeeper
}
-rule_filesystem_init () {
- mk_reg mod=644 own=root:root /etc/fstab <<-EOF
+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_initramfs_init () {
- mk_reg mod=644 own=root:root /etc/initramfs-tools/initramfs.conf <<-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
- mk_reg mod=644 own=root:root /etc/modprobe.d/xen-pv.conf <<-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
- mk_reg mod=644 own=root:root /etc/modules <<-EOF
+ sudo install -m 644 -u root -g root /dev/stdin /etc/modules <<-EOF
sha1_generic
sha256_generic
sha512_generic
# NOTE: pour Xen en mode HVM :
#modprobe xen-platform-pci
EOF
- mk_reg mod=644 own=root:root /etc/initramfs-tools/modules <<-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é..
- 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
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
- 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 \
+ }
+ # 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 |
cat "$home"/etc/ssh/authorized_keys
done
done |
- mk_reg mod=644 own=root:root /etc/initramfs-tools/root/.ssh/authorized_keys
+ 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 \
# NOTE: clefs générées par Debian
sudo update-initramfs -u
}
-rule_locale_init () {
- mk_reg mod=644 own=root:root /etc/locale.gen <<-EOF
+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_init () {
+rule_login_configure () {
grep -q '^hvc0$' /etc/securetty ||
- mk_reg mod= own= --append /etc/securetty <<-EOF
+ 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
+ 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.
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
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_network_init () {
- mk_reg mod= own= /etc/hostname <<-EOF
+rule_network_configure () {
+ sudo install -m 644 -u root -g root /dev/stdin /etc/hostname <<-EOF
$vm
EOF
grep -q " $vm\$" /etc/hosts ||
- mk_reg mod= own= --append /etc/hosts <<-EOF
+ 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= own= /etc/network/interfaces <<-EOF
+ sudo install -m 644 -u root -g root /dev/stdin /etc/network/interfaces <<-EOF
auto lo
iface lo inet loopback
network $vm_ipv4
broadcast $vm_ipv4
netmask 255.255.255.255
- #mtu 1300
+ 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
}
-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
/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 ::
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 \\
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_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
+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 test -n "$users" && IFS=: read -r group x x users
- do while IFS=, read -r user users <<-EOF
+ 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 |
- mk_reg mod=640 own=root:root /root/etc/ssh/authorized_keys
- local key
+ 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_init () {
- mk_lnk "$tool"/vm_hosted /usr/local/sbin/
+rule_bin_configure () {
+ sudo ln -fns "$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_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_disk_key_change () {
+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 ||
# 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
- mk_reg mod=640 own=$user:$user "$home"/etc/ssh/authorized_keys \
- <"$tool"/var/pub/ssh/"$user".key
- rule initramfs_init
- rule user_root_init
+ 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
mk_reg mod=664 own=root:root /etc/postgrey/whitelist_recipients.local <<-EOF
EOF
}
-rule_mail_init () {
+rule_mail_configure () {
sudo apt-get install postfix postgrey dovecot
}
(help);;
(*)
assert 'test "$(hostname --fqdn)" = "$vm_fqdn"' vm_fqdn
- ${TRACE:+set -x}
;;
esac
rule $rule "$@"