Após o tar falhar, o script sai sem manipular o erro

1

Então, eu tenho um script de backup que se parece 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 logar corretamente no 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 tive uma falha na compactação devido a um disco cheio, comportamento esperado, como você pode imaginar para o 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, depois passou pela condição if , de alguma forma ignorou o logging "ERROR: ..." , executou o df -h e morreu. ignorando o resto.

De alguma forma parece que está pular qualquer função, mas executando os comandos.

O backup é chamado de um arquivo cron.d . Eu não defini set -e , então nenhuma saída de erro é feita.

Alguma idéia de por que isso está acontecendo?

    
por TanisDLJ 28.08.2018 / 10:58

2 respostas

2

Seu script parece funcionar como esperado. A saída de df alcançou claramente $LOG_FILE e exit 1 está fazendo o script sair.

Não sabemos o que faz o seu comando logging , mas AFAICT, não se destina a gravar em $LOG_FILE . Se fosse, seria um pouco bobo escrever Verifique o arquivo de log: $ {LOG_FILE} lá.

Editar

Agora que você postou a função logging , posso ver que ela usa uma string aqui ( <<< ).

Em bash , here-strings e here-documents são implementados usando arquivos temporários (em $TMPDIR ou /tmp if $TMPDIR não está definido). Se esse fosse o sistema de arquivos que estava cheio, isso explicaria porque logging não produziu 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}"

Use apenas:

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 que $IFS não está definido ou começa com espaço)

Isso salva o arquivo temporário, mas também evita a falsificação de qualquer processo ou a execução de qualquer comando externo (que também pode falhar sob algumas condições patológicas) (e oferece um formato de data mais útil, sinta-se à vontade para se adaptar).

Geralmente, um sistema com um sistema de arquivos / tmp e / var completo é um sistema danificado; é possível esperar que muitas coisas não funcionem adequadamente.

Aqui, você tem sorte de ter registros. O espaço em disco para arquivos é alocado em blocos (geralmente 4K em ext4), o que provavelmente é o motivo pelo qual você obteve alguma saída em '$ LOG_FILE (como o último bloco foi alocado antes do sistema de arquivos ficar cheio).

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 o conteúdo se não estiver vazio). Portanto, qualquer um dos comandos pode ter seu write(1, ...) ou write(2, ...) também falhar (com erro ENOSPC), o que poderia fazer com que eles se comportassem mal ou saíssem mais cedo se considerassem um erro fatal.

    
por 28.08.2018 / 12:14
1

Existe uma grande probabilidade de que o problema seja que

PACKING_EXITCODE=${PIPESTATUS[0]}

não é um código de shell válido, mas algo que é bash específico.

Cron chama comandos com /bin/sh que difere de bash .

Você pode deixar seu script começar com

#!/bin/bash

e torne o script executável usando chmod +x scriptname para garantir que o código bash específico seja executado por bash e não pelo shell padrão.

    
por 28.08.2018 / 12:04