#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
source "$(dirname "$0")/lib/ulib/ulib" || exit 1
urequire DEFAULTS template apache.tools

function display_help() {
    uecho "$scriptname: Gérer une configuration apache pour déploiement

USAGE
    $scriptname [options]

OPTIONS
Les options suivantes servent à mettre à jour la configuration apache dans un
répertoire de référence appelé répertoire local, avant son déploiement.
    -d, --destdir DESTDIR
        Spécifier le répertoire local dans lequel copier la configuration
        apache.
    -l, --list
        Lister les templates disponibles.
    -m, --merge
        Copier les templates spécifiés dans le répertoire local s'il n'y
        existent pas déjà. Les templates ayant l'extension '.template' doivent
        être demandés explicitement. Sinon, ils sont ignorés.
    -z, --unmerge
        Supprimer les fichiers du répertoire local s'ils n'ont pas été modifiés
        par rapport aux templates.
    -C, --clean
        Supprimer les répertoires vides dans le répertoire local. Peut être
        utile après -z
    -g, --diff
        Afficher les différences entre les templates et les fichiers du
        répertoire local.
    --list-vars
        Afficher pour information les valeurs par défaut des variables de
        template.
    --write-vars
        Ecrire dans le fichier .apacheconfig les valeurs par défaut des
        variables, ce qui permet après édition du fichier d'éviter de les
        spécifier à chaque fois avec l'option -v
        Le fichier n'est pas écrasé s'il existe déjà.
    -v, --var NAME=VALUE
        Spécifier la valeur d'une variable. Il est possible de spécifier des
        valeurs qui ne sont pas dans la liste prédéfinie. Par défaut, il s'agit
        d'une variable de template, utilisée pour mettre à jour la copie locale
        d'un template avec l'option --merge
        Dans le fichier .apacheconfig, les valeurs des variables de template
        n'est pas censée changer. Lors de la copie des templates avec --merge,
        chaque occurence de @@VAR@@ dans un template est remplacée dans la copie
        locale par la valeur de la variable de template VAR
        Les variables dynamiques sont remplacées lors du déploiement du fichier
        avec l'option --update

Le répertoire local peut contenir les fichiers et répertoires suivants, qui sont
tous optionnels:

- modules.conf la liste des modules qu'il faut activer. Si un module n'existe
  pas dans ce fichier, ou si ce fichier n'existe pas, aucune modification n'est
  effectuée. Si un module est de la forme -module, il est désactivé. Si un
  module est de la forme +module, il est activé. Cette syntaxe permet de
  supporter les modules dont le nom commencerait par '-'
- sites.conf la liste des sites qu'il faut activer. Si un site ne figure pas
  dans ce fichier, il est désactivé. Si ce fichier n'existe pas, tous les sites
  existant sont activés.
- tous les autres fichiers sont copiés tels quels dans /etc/apache2. Notamment,
  apache2.conf est le fichier de configuration principal d'apache et ports.conf
  le fichier de configuration des ports d'écoute.
- modules/ le répertoire des configurations de modules à installer. Les fichiers
  de ce répertoire sont de la forme MODULE.conf et sont installés dans le
  répertoire /etc/apache2/mods-available. Il faut mentioner le module dans le
  fichier modules.conf pour l'activer.
- sites/ le répertoire des sites à installer. Les fichiers de ce répertoire sont
  de la forme NAME.conf pour les sites écoutant en clair, et NAME.ssl.conf pour
  les sites écoutant en https. Pour chaque site NAME.ssl.conf, un fichier
  NAME-certs.conf doit exister dans certsconf/
  Dans les fichiers NAME.ssl.conf, les valeurs @@cert@@, @@key@@ et @@ca@@ sont
  respectivement remplacées par l'emplacement des fichiers de certificats
  définis dans les fichiers correspondants NAME-certs.conf
- cgi-bin/ le répertoire des scripts cgi à installer
- www/ le répertoire qui contient les fichiers du serveur web à installer dans
  l'emplacement par défaut.
- certsconf/ le répertoire qui contient la configuration pour les certificats à
  installer. Si ce répertoire existe, il faut spécifier CERTSDIR
  Les fichiers de ce répertoire sont de la forme NAME-certs.conf et chacun d'eux
  correspondant en principe à un fichier NAME.ssl.conf dans sites/
- RewriteRules/ le répertoire qui contient la configuration de réécriture. Tous
  les fichiers RewriteRules*.conf de ce répertoire sont copiés dans /etc/apache2

Les options suivantes permettent de déployer les fichiers du répertoire local.
IMPORTANT: les fonctions de déploiement ne sont pour le moment supportées que
sur debian
    -u, --update, --deploy
        Mettre à jour la configuration système à partir du répertoire local.
        Lors du déploiement de la configuration, les valeurs de variables
        dynamiques sont remplacées dans les fichiers destination.
    -r, --certsdir CERTSDIR
        Spécifier le cas échéant le répertoire contenant les certificats à
        déployer.

OPTIONS AVANCEES
    --confdir CONFDIR
        Spécifier l'emplacement des fichiers de configuration apache ainsi que
        les fichiers 'modules.conf' et 'sites.conf'. Par défaut, prendre le
        répertoire local.
    --modulesdir MODULESDIR
        Spécifier l'emplacement des fichiers de configuration des modules. Par
        défaut, utiliser DESTDIR/modules si ce répertoire existe.
    --sitesdir SITESDIR
        Spécifier l'emplacement des fichiers de configuration des sites. Par
        défaut, utiliser DESTDIR/sites si ce répertoire existe.
    --cgibindir CGIBINDIR
        Spécifier l'emplacement des scripts cgi à installer. Par défaut,
        utiliser DESTDIR/cgi-bin si ce répertoire existe.
    --wwwdir WWWDIR
        Spécifier l'emplacement des fichiers du serveur web. Par défaut,
        utiliser DESTDIR/www si ce répertoire existe.
    --certsconfdir CERTSCONFDIR
        Spécifier l'emplacement des fichiers de configuration des certificats.
        Par défaut, utiliser DESTDIR/certsconf si ce répertoire existe. Il faut
        alors spécifier aussi CERTSDIR, l'emplacement des certificats à
        installer.
    --rrdir RRDIR
        Spécifier l'emplacement des fichiers de réécriture. Par défaut,
        utiliser DESTDIR/RewriteRules si ce répertoire existe.
    --no-restart
        Ne pas redémarrer apache en cas de modification de la configuration"
}
function __templatectl_display_help() { display_help; }

# Valeurs par défaut des variables de template
DEFAULT_TEMPLATE_VARS=(
    hostname= aliases= # mettre ces variables AVANT host
    host=
    admin=supervision-gdrsi@listes.univ-reunion.fr
    certsdir=renater
    caname=terena.crt
    certname=
    keyname=
    #configdir= # défini ci-dessous
)

function parent_apacheconfig() {
    # chercher à partir du répertoire courant si un des répertoires parents
    # s'appelle apacheconfig
    local dir="$(pwd)" dirname
    
    while true; do
        dirname="$(basename -- "$dir")"
        if [ "$dir" == / ]; then
            # s'arrêter à la racine
            return 1
        elif [ "$dir" == "$HOME" ]; then
            # s'arrêter au répertoire HOME
            return 1
        elif [ "$dirname" == apacheconfig ]; then
            echo "$dir"
            return 0
        fi
        dir="$(dirname -- "$dir")"
    done
}

TEMPLATE_VARS=()
DYNAMIC_VARS=()
function update_var() {
    # mettre à jour la valeur d'une variable en tenant compte de certaines
    # dépendances. par exemple, si on modifie host, il faut mettre à jour
    # hostname.
    local __orig_value="${!1}"
    array_contains DYNAMIC_VARS "$1" || array_addu TEMPLATE_VARS "$1"

    # Valeurs par défaut
    case "$1" in
    host) [ -n "$2" ] || set -- "$1" "$(myhost)";;
    esac

    # Mettre à jour la variable
    setv "$1" "$2"

    # Mettre à jour des variables dépendantes
    local __update_aliases
    case "$1" in
    host)
        # attention à ne pas créer de boucle infinies :-)
        [ "$aliases" == "$hostname" ] && __update_aliases=1
        update_var hostname "${host%%.*}"
        [ -n "$__update_aliases" ] && update_var aliases "$hostname"
        ;;
    esac

    [ "$2" != "$__orig_value" ]
}

__vars=()
__list_vars=
__write_vars=
__deploy=
__certsdir=
__confdir=
__modulesdir=
__sitesdir=
__cgibindir=
__wwwdir=
__certsconfdir=
__rrdir=
__restart=1
__TEMPLATECTL_SUPPLOPTS=(
    -v:,--var: __vars
    --list-vars __list_vars=1
    --write-vars __write_vars=1
    -u,--update,--deploy __deploy=1
    -r:,--certsdir: __certsdir=
    --confdir: __confdir=
    --modulesdir: __modulesdir=
    --sitesdir: __sitesdir=
    --cgibindir: __cgibindir=
    --wwwdir: __wwwdir=
    --certsconfdir: __certsconfdir=
    --rrdir: __rrdir=
    --restart __restart=1
    --no-restart __restart=
)
__templatectl_parseopts "$@" && \
    set -- "${args[@]}" || die "$args"

# répertoire de template
setx __templatectl_srcdir=templatesrc apacheconfig

# répertoire local
__autocreate=
if [ -z "$__templatectl_destdir" ]; then
    if [ -d apacheconfig ]; then
        __templatectl_destdir=apacheconfig
    elif setx __templatectl_destdir=parent_apacheconfig; then
        estepn "Sélection automatique de $(ppath "$__templatectl_destdir")"
    elif [ -e apacheconfig ]; then
        die "Vous devez spécifier le répertoire de référence avec -d"
    else
        __templatectl_destdir=apacheconfig
        __autocreate=1
    fi
fi
setx __templatectl_destdir=abspath "$__templatectl_destdir"

# charger les variables. important: la liste des variables définie dans le
# fichier .apacheconfig prend la précédence sur la liste définie par défaut
__template_vars=("${DEFAULT_TEMPLATE_VARS[@]}")
__dynamic_vars=()
__apacheconfig_vars="$__templatectl_destdir/.apacheconfig"
# d'abord charger __template_vars
[ -f "$__apacheconfig_vars" ] && source "$__apacheconfig_vars"
for __var in "${__template_vars[@]}"; do
    splitvar "$__var" __name __value
    update_var "$__name" "$__value"
done
array_contains TEMPLATE_VARS configdir || update_var configdir "$__templatectl_destdir"
# puis charger __dynamic_vars
[ -f "$__apacheconfig_vars" ] && source "$__apacheconfig_vars"
for __var in "${__dynamic_vars[@]}"; do
    splitvar "$__var" __name __value
    array_del TEMPLATE_VARS "$__name"
    array_addu DYNAMIC_VARS "$__name"
    update_var "$__name" "$__value"
done

# mettre à jour les variables
__modified=
for __var in "${__vars[@]}"; do
    splitvar "$__var" __name __value
    update_var "$__name" "$__value" && __modified=1
done

# enregistrer les valeurs des variables
if [ -n "$__write_vars" ]; then
    [ -f "$__apacheconfig_vars" ] &&
    die "Refus d'écraser le fichier existant $(ppath "$__apacheconfig_vars")"

    echo "# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8" >"$__apacheconfig_vars"
    echo "__template_vars=(" >>"$__apacheconfig_vars"
    for __var in "${TEMPLATE_VARS[@]}"; do
        echo_setv "$__var=${!__var}" >>"$__apacheconfig_vars"
    done
    echo ")" >>"$__apacheconfig_vars"
    echo "__dynamic_vars=(" >>"$__apacheconfig_vars"
    for __var in "${DYNAMIC_VARS[@]}"; do
        echo_setv "$__var=${!__var}" >>"$__apacheconfig_vars"
    done
    echo ")" >>"$__apacheconfig_vars"
fi

# afficher les variables
if [ -n "$__list_vars" ]; then
    echo "# template vars"
    for __var in "${TEMPLATE_VARS[@]}"; do
        echo_setv "$__var=${!__var}"
    done
    if [ ${#DYNAMIC_VARS[*]} -gt 0 ]; then
        echo "# dynamic vars"
        for __var in "${DYNAMIC_VARS[@]}"; do
            echo_setv "$__var=${!__var}"
        done
    fi
fi

# Gérer les templates et fichiers locaux
if [ -z "$__templatectl_opt" -a -z "$__list_vars" -a -z "$__write_vars" -a -z "$__deploy" ]; then
    __templatectl_opt=1
    __templatectl_auto=1
fi
if [ -n "$__templatectl_opt" ]; then
    if [ -n "$__autocreate" -a ! -d "$__templatectl_destdir" ]; then
        estepn "Création automatique de $(ppath "$__templatectl_destdir")"
        mkdir -p "$__templatectl_destdir" || die
    fi
    [ -d "$__templatectl_destdir" ] || die "$__templatectl_destdir: répertoire introuvable"
    __templatectl_do "$@"
fi

# déploiement
if [ -n "$__deploy" ]; then
    args=(
        -d "$__templatectl_destdir"
        -u
        ${__certsdir:+-r "$__certsdir"}
        ${__confdir:+--confdir "$__confdir"}
        ${__modulesdir:+--modulesdir "$__modulesdir"}
        ${__sitesdir:+--sitesdir "$__sitesdir"}
        ${__cgibindir:+--cgibindir "$__cgibindir"}
        ${__wwwdir:+--wwwdir "$__wwwdir"}
        ${__certsconfdir:+--certsconfdir "$__certsconfdir"}
        ${__rrdir:+--rrdir "$__rrdir"}
    )
    for __name in "${DYNAMIC_VARS[@]}"; do
        array_add args -v "$__name=${!__name}"
    done
    run_as_root "${args[@]}"

    etitle "Mise à jour du système"
    [ -d "$__templatectl_destdir" ] || die "$__templatectl_destdir: répertoire introuvable"
    args=(
        "$__templatectl_destdir" "$__certsdir"
        ${__confdir:+--confdir "$__confdir"}
        ${__modulesdir:+--modulesdir "$__modulesdir"}
        ${__sitesdir:+--sitesdir "$__sitesdir"}
        ${__cgibindir:+--cgibindir "$__cgibindir"}
        ${__wwwdir:+--wwwdir "$__wwwdir"}
        ${__certsconfdir:+--certsconfdir "$__certsconfdir"}
        ${__rrdir:+--rrdir "$__rrdir"}
    )
    for __name in "${DYNAMIC_VARS[@]}"; do
        array_add args "$__name=${!__name}"
    done
    apache_autoconf "${args[@]}" || die
    eend
fi
