2019-05-25 17:36:24 -03:00

170 lines
4.7 KiB
Django/Jinja

#!/bin/bash
# Ansible-generated LDAP backup script
#
# usage: ldap_backup.sh DN DIRECTORY KEEP
# where:
# DN is the base DN to backup
# DIRECTORY is where to save the backup
# KEEP number of backups to keep
# utility functions
msg(){ ${VERBOSE:-true} && echo ${@} ; }
assert(){ [[ ${?} -eq 0 ]] || { [[ -n ${1} ]] && { msg ; msg ${@} ; } ; exit 1 ; } }
warn(){ [[ ${?} -eq 0 ]] || { [[ -n ${1} ]] && msg ${@} ; return 1 ; } }
# All DNs configured on this server
ALL_DNs="{{ backup_domains | default([]) | union(['cn=config']) | join(' ')}}"
BACKUP_DIR="{{ openldap_backup_dir }}"
# Restaurar backup dado por argumento, puede ser un DN o un archivo de backup
restaurar(){
local ARG=${1}
local DN=""
local LDIF=""
if [[ -f "${ARG}" ]]
then
# el argumento es un archivo, se debe adivinar el DN
DN="$(zcat -f ${ARG}| head -n1 | egrep '^dn:' | awk '{print $2}')"
LDIF="$(realpath ${ARG})"
else
# se toma el argumento como un DN, se debe encontrar el archivo
DN="${ARG}"
LDIF=$(find ${BACKUP_DIR} -type f -iname "*.ldif*" -print0 | xargs -0 zegrep -l "^dn: ${DN}\$" | sort | tail -n1)
fi
[[ -n "${LDIF}" ]]
assert "ERROR: no se encontró un backup para restaurar ${DN}. " \
"Por favor indíquelo como argumento."
[[ "$(systemctl is-active slapd.service)" == "inactive" ]]
assert "FATAL: El servicio slapd.service está activo."
# # validar que el DN es el correcto
# zcat -f "${LDIF}" | head -n1 | egrep -q "^dn: ${DN}\$"
# assert -e "FATAL: El archivo ${LDIF} no corresponde al DN ${DN}.\n\n" \
# "Se esperaba como primer línea... dn: ${DN} \n" \
# "Sin embargo, se encontró........ $( zcat -f "${LDIF}" | head -n1 )\n"
# Determinar directorio de la base de datos y opciones de slapadd
# Caso general (datos)
DATA_DIR="/var/lib/ldap/${DN}"
SLAPADD_SW="{{ '-w' if openldap_provider else '' }}"
# Caso especial cn=config
[[ "${DN}" == "cn=config" ]] && {
DATA_DIR="/etc/ldap/slapd.d"
SLAPADD_SW="-F /etc/ldap/slapd.d/"
}
# Nombre de la carpeta de backup
DATA_DIR_BAK="${DATA_DIR}.backup-$(date +%Y%m%d%H%M%S)"
msg "Guardando backup en ${BACKUP_DIR}"
mv "${DATA_DIR}" "${DATA_DIR_BAK}"
mkdir "${DATA_DIR}"
msg "Cargando datos de ${DN} desde ${LDIF}"
zcat -f "${LDIF}" | slapadd -b "${DN}" ${SLAPADD_SW}
assert -e "FATAL: Error durante la restauración.\n" \
"Puede volver al estado anterior renombrando ${DATA_DIR_BAK} -> ${DATA_DIR} " \
"antes de volver a iniciar slapd."
msg "Cambiando owner de ${DATA_DIR}"
chown -R openldap:openldap "${DATA_DIR}"
msg "Se ha restaurado correctamente ${DN}."
return 0
}
ayuda() {
cat<<EOF
${0##*/} restaura el árbol LDAP desde backup
Uso:
${0##*/} [-y] [-i] [ DN_O_ARCHIVO ] [ DN_O_ARCHIVO ] [ ... ]
Cada argumento DN_O_ARCHIVO refiere a un DN o a un archivo LDIF:
* si es un DN, se busca el último backup de ese DN y se lo restaura
* si es un archivo LDIF, se carga directamente ese archivo al servidor
La búsqueda de backups (cuando se especifica DN) se realiza en el directorio:
${BACKUP_DIR}
NOTA: Si no se especifica ningún DN o archivo, se intentará restaurar los
siguientes DN: ${ALL_DNs}
Opciones:
-y confirmar operación, necesaria para restaurar
-i modo interactivo, preguntar antes de pisar la base
-h mostrar esta ayuda
EOF
exit ${1:-0}
}
# Opciones de seguridad para evitar una restauracion accidental
# Obligatorio pasar el argumento -y o bien -i
CONFIRMADO=false
INTERACTIVO=false
while getopts "y i h" OPCION
do
case ${OPCION} in
"y")
CONFIRMADO=true
;;
"i")
INTERACTIVO=true
;;
"h")
ayuda 0
;;
*)
ayuda 2
;;
esac
done
# des-setear -y si se paso -i
${INTERACTIVO} && CONFIRMADO=false
# filtrar argumentos tipo -y
ARGS=""
for ARG in ${@}
do [[ ${ARG} =~ ^-.$ ]] || ARGS="${ARGS} ${ARG}"
done
# Si no se especifica, restaurar todos los DNs
if [[ -z ${ARGS} ]]
then ARGS="${ALL_DNs}"
fi
${CONFIRMADO} || ${INTERACTIVO}
warn "ERROR: Debe especificar alguna de las opciones -i o -y" || ayuda 2
command -v /usr/sbin/slapadd > /dev/null
assert "ERROR: no se encuentra 'slapadd', por favor instale ldap-utils."
${INTERACTIVO} && {
msg -e "Se restaurarán los siguientes DNs/archivos:\n ${ARGS}"
msg "Esto causará la PÉRDIDA DE LOS DATOS ACTUALES en el directorio."
msg -n "¿Confirma que está seguro? (s/n) "
read TECLA
[[ "${TECLA,,}" == "s" ]] || {
msg "Abortando operación: no se realiza ningún cambio."
exit 3;
}
}
# Detener servidor antes de restaurar
msg "Deteniendo servicio slapd..."
systemctl stop slapd.service
# restaurar todo
for ARG in ${ARGS}
do restaurar ${ARG}
done
msg "Reiniciando servicio slapd..."
systemctl start slapd.service