170 lines
4.7 KiB
Django/Jinja
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
|