
Entonces, tengo un script de respaldo que se ve así:
tar -cf "${BACKUP_TAR}" "${LATEST_SUCCESSFUL_BACKUP}" 2>&1 | tee -a "${LOG_FILE}"
local PACKING_EXITCODE=${PIPESTATUS[0]}
if [ ${PACKING_EXITCODE} -eq 0 ]; then
logging 'Packing successful'
else
logging "ERROR: Packing failed! ERROR: ${PACKING_EXITCODE}. Disk space?"
df -h 2>&1 | tee -a "${LOG_FILE}"
logging "Check the log file: ${LOG_FILE}"
set_lockfile 'destroy'
backup_remove_package
exit 1
fi
logging
es una función para iniciar sesión correctamente en mi archivo de registro.
logging () {
local now="$(date)"
local logfile=$2
local logfile=${logfile:-$LOG_FILE}
cat <<< "${now} $@" | tee -a "${logfile}"
}
set_lockfile "destroy"` es una función que elimina mi archivo de bloqueo.
set_lockfile () {
local lockfile_action=$1
local lockfile=$2
local lockfile=${lockfile:-$LOCK_FILE}
if [ "${lockfile_action}" == "create" ]; then
#...
elif [ "${lockfile_action}" == "destroy" ]; then
destroy_lockfile $lockfile
else
logging 'ERROR: Wrong argument for locking file: use create or destroy'
exit 1
fi
}
destroy_lockfile () {
local lockfile=$1
if [ ! -f ${lockfile} ]; then
logging "WARNING: Lockfile ${lockfile} not found!"
else
logging "Removing lockfile ${lockfile}"
rm -f "${lockfile}"
fi
}
backup_remove_package
es una función para eliminar cualquier archivo temporal creado.
Experimento un embalaje fallido debido a un disco lleno, comportamiento esperado como puedes adivinar para el archivo df -h
.
Lo interesante es el registro de respaldo. Afirma:
tar: /tmp/backup/20180827T223001.tar: Wrote only 4096 of 10240 bytes
tar: Error is not recoverable: exiting now
Filesystem Size Used Avail Use% Mounted on
/dev/xvda1 788G 788G 0 100% /
devtmpfs 3.9G 60K 3.9G 1% /dev
tmpfs 3.9G 0 3.9G 0% /dev/shm
Lo que significa que tar
falló, luego pasó por la if
condición, de alguna manera se saltó el logging "ERROR: ..."
, ejecutó el df -h
y murió. saltándose el resto.
De alguna manera parece que se está saltando cualquier función pero ejecutando los comandos.
La copia de seguridad se llama desde un cron.d
archivo. NO lo he configurado set -e
, por lo que no se realiza ninguna salida en caso de error.
¿Alguna idea de por qué sucede esto?
Respuesta1
Su secuencia de comandos parece funcionar como se esperaba. La salida de df
claramente llegó $LOG_FILE
y exit 1
está provocando que el script se cierre.
No sabemos qué logging
hace su comando, pero AFAICT, no está destinado a escribir $LOG_FILE
. Si así fuera, sería un poco tonto escribirVerifique el archivo de registro: ${LOG_FILE}allá.
Editar
Ahora que ha publicado la logging
función, puedo ver que utiliza una cadena aquí ( <<<
).
En bash
, las cadenas aquí y los documentos aquí se implementan mediante archivos temporales (en $TMPDIR
o /tmp
si $TMPDIR
no están definidos). Si ese fuera el sistema de archivos que estaba lleno, eso explicaría por qué logging
no generó nada.
$ sudo mount -o size=1 -t tmpfs empty /mnt/1
$ yes > /mnt/1/fill-up
yes: standard output: No space left on device
$ TMPDIR=/mnt/1 bash -c 'cat <<< test'
bash: cannot create temp file for here-document: No space left on device
En lugar de:
local now="$(date)"
cat <<< "${now} $@" | tee -a "${logfile}"
Solo usa:
printf '%(%FT%T%z)T %s\n' -1 "$*"
printf '%(%FT%T%z)T %s\n' -1 "$*" >> "$logfile"
O:
local msg
printf -v msg '%(%FT%T%z)T %s' -1 "$*"
printf '%s\n' "$msg"
printf '%s\n' "$msg" >> "$logfile"
(se supone $IFS
que no está configurado o comienza con un espacio)
Eso guarda el archivo temporal, pero también evita bifurcar cualquier proceso o ejecutar cualquier comando externo (que también podría fallar bajo algunas condiciones patológicas) (y le brinda un formato de fecha más útil, siéntase libre de adaptarlo).
En términos más generales, un sistema con un sistema de archivos /tmp y /var completo es un sistema dañado y se puede esperar que muchas cosas no funcionen correctamente.
Aquí tienes suerte de tener registros. El espacio en disco para los archivos se asigna en bloques (normalmente 4K en ext4), por lo que probablemente obtuvo algunos resultados en `$LOG_FILE (ya que el último bloque se asignó antes de que se llenara el sistema de archivos).
Los scripts ejecutados por cron también tienen su stdout y stderr en un archivo temporal (luego cron intenta enviar un correo electrónico con su contenido si no están vacíos). Por lo tanto, cualquiera de los comandos podría fallar write(1, ...)
o write(2, ...)
fallar también (con un error ENOSPC), lo que podría provocar que se comporten mal o salgan antes de tiempo si lo consideran un error fatal.
Respuesta2
Hay una alta probabilidad de que el problema sea que
PACKING_EXITCODE=${PIPESTATUS[0]}
No hay un código de shell válido sino algo bash
específico.
Cron llama a comandos /bin/sh
que difieren de bash
.
Podrías dejar que tu guión comience con
#!/bin/bash
y haga que el script sea ejecutable chmod +x scriptname
para asegurarse de que el bash
código específico se ejecute mediante bash
el shell predeterminado y no mediante él.