
Então, eu tenho um script de backup parecido com:
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
é uma função para efetuar login corretamente em meu arquivo de log.
logging () {
local now="$(date)"
local logfile=$2
local logfile=${logfile:-$LOG_FILE}
cat <<< "${now} $@" | tee -a "${logfile}"
}
set_lockfile "destroy"` é uma função que remove meu arquivo de bloqueio.
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
é uma função para remover quaisquer arquivos temporários criados.
Eu experimentei uma falha na compactação devido a um comportamento esperado do disco cheio, como você pode imaginar para o arquivo df -h
.
O interessante é o log de backup. 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
O que significa que tar
falhou, então passou pela if
condição, de alguma forma ignorou o logging "ERROR: ..."
, executou o df -h
e morreu. pulando o resto.
De alguma forma, parece que está pulando qualquer função, mas executando os comandos.
O backup é chamado de um cron.d
arquivo. Eu NÃO configurei set -e
, então nenhuma saída em caso de erro é feita.
Alguma idéia de por que isso está acontecendo?
Responder1
Seu script parece funcionar conforme o esperado. A saída de df
claramente chegou $LOG_FILE
e exit 1
está fazendo com que o script seja encerrado.
Não sabemos o que o seu logging
comando faz, mas AFAICT, ele não foi feito para gravar em arquivos $LOG_FILE
. Se fosse, seria um pouco bobo escreverVerifique o arquivo de registro: ${LOG_FILE}lá.
Editar
Agora que você postou a logging
função, posso ver que ela usa uma string aqui ( <<<
).
Em bash
, here-strings e here-documents são implementados usando arquivos temporários (in $TMPDIR
ou /tmp
if $TMPDIR
não está definido). Se esse fosse o sistema de arquivos que estava cheio, isso explicaria por que logging
não gerou 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
Em vez de:
local now="$(date)"
cat <<< "${now} $@" | tee -a "${logfile}"
Apenas use:
printf '%(%FT%T%z)T %s\n' -1 "$*"
printf '%(%FT%T%z)T %s\n' -1 "$*" >> "$logfile"
Ou:
local msg
printf -v msg '%(%FT%T%z)T %s' -1 "$*"
printf '%s\n' "$msg"
printf '%s\n' "$msg" >> "$logfile"
(assume $IFS
que não está definido ou começa com espaço)
Isso salva o arquivo temporário, mas também evita a bifurcação de qualquer processo ou a execução de qualquer comando externo (que também pode falhar sob algumas condições patológicas) (e fornece um formato de data mais útil, fique à vontade para adaptar).
De forma mais geral, um sistema com um sistema de arquivos /tmp e /var completo é um sistema danificado, você pode esperar que muitas coisas não funcionem corretamente.
Aqui, você tem sorte de ter registros. O espaço em disco para arquivos é alocado em blocos (normalmente 4K no ext4), e é provavelmente por isso que você obteve alguma saída em `$LOG_FILE (já que o último bloco foi alocado antes do sistema de arquivos ficar cheio).
Os scripts executados pelo cron também têm stdout e stderr em um arquivo temporário (então o cron tenta enviar um email com seu conteúdo se não estiverem vazios). Portanto, qualquer um dos comandos também pode write(1, ...)
falhar write(2, ...)
(com erro ENOSPC), o que pode fazer com que eles se comportem mal ou saiam mais cedo se considerarem um erro fatal.
Responder2
Há uma grande probabilidade de que o problema seja esse
PACKING_EXITCODE=${PIPESTATUS[0]}
não há código de shell válido, mas algo específico bash
.
Cron chama comandos /bin/sh
diferentes do bash
.
Você poderia deixar seu script começar com
#!/bin/bash
e torne o script executável usando chmod +x scriptname
para garantir que o bash
código específico seja executado bash
e não pelo shell padrão.