Adicione algo ao crontab programaticamente (por ssh)

8

Eu tenho um script de implantação, ele deve adicionar algo a um usuário crontab (acionar um script que limpa logs a cada XXX dias), no entanto, isso só deve ser feito durante a primeira implantação ou quando precisar ser atualizado.

(posso executar xxx.py deploy env ou xxx.py update env )

então tenho que fazer isso:

Check if my cronJob already exist
Put my cronJob if it does not already exist
or
update my cronjob if one of the parameter of the command is different

Não vejo como adicionar / verificar / remover algo para o crontab sem usar crontab -e ou editar o arquivo crontab (baixe-o, reescreva-o, faça o upload novamente)

PS: este é um cronjob específico do usuário, "webadmin" vai fazer isso e ele não deve usar o sudo para fazer isso.

    
por sliders_alpha 21.07.2016 / 15:05

5 respostas

9

minha melhor ideia até agora

para verificar primeiro se o conteúdo corresponde ao que deve estar lá e apenas atualizá-lo, se não corresponder:

if [[ $(crontab -l | egrep -v "^(#|$)" | grep -q 'some_command'; echo $?) == 1 ]]
then
    echo $(crontab -l ; echo '* 1 * * * some_command') | crontab -
fi

mas isso fica complicado o suficiente para criar um script separado em torno dessa tarefa cron.

outras ideias

você pode enviar a string via stdin para crontab (cuidado, isso limpa todas as entradas anteriores do crontab):

echo "* 1 * * * some_command" | crontab -

isto deve funcionar mesmo através do ssh:

echo "* 1 * * * some_command" | ssh user@host "crontab -"

se você quiser acrescentar ao arquivo, você pode usar isto:

# on the machine itself
echo "$(echo '* 1 * * * some_command' ; crontab -l)" | crontab -
# via ssh
echo "$(echo '* 1 * * * some_command' ; ssh user@host crontab -l)" | ssh user@host "crontab -"
    
por 21.07.2016 / 15:15
2

Para o registro, vou sugerir o uso de /etc/cron.d/ . Apenas o root pode gravar arquivos aqui, mas as entradas podem ser executadas como qualquer usuário (sem necessidade de sudo ).

echo '0 0 * * 0 webadmin /usr/local/bin/tidy_logfiles' > ~/webadmin.cron
scp -p ~/webadmin.cron root@remote_host:/etc/cron.d/webadmin

Isso pode ser aplicado várias vezes, atualizando o arquivo webadmin.cron local, conforme necessário, antes de copiá-lo.

Você pode até mesmo remover o provisionamento:

ssh -q root@remote_host rm -f /etc/cron.d/webadmin

Observe que, em muitos casos, você não pode fornecer a senha do root para os comandos scp / ssh . Em vez disso, você precisa ter certificados de chave pública / privada. Além disso, por implicação, a conta local (seja ela qual for) terá acesso root completo ao servidor remoto. Não está claro no momento se isso seria um obstáculo para o seu cenário específico.

    
por 21.07.2016 / 17:19
2

Eu recomendo usar o Ansible * para isso, em vez de usar o seu próprio. Ou Puppet ou Chef - mas o Ansible é bem adequado para scripts de implantação com infraestrutura zero como este.

Isso porque já existem módulos destinados a resolver problemas como esse, e as ferramentas de gerenciamento de configuração têm idempotência como base meta de design - essa é a propriedade de apenas mudar quando necessário, mesmo que você acidentalmente (ou intencionalmente) a execute novamente.

Em particular, o módulo cron do Ansible pode modificar os crontabs do usuário. Como um bônus, se você quiser ajustar mais tarde para usar crontabs do sistema, será um ajuste muito fácil em vez de uma reescrita.

* aviso: Eu trabalho para a Red Hat, e Ansible é um projeto patrocinado pela Red Hat.

    
por 21.07.2016 / 17:32
0

Se você quiser adicionar uma tarefa cron por meio da conta de destino, execute crontab -e . Este comando passa o crontab através de um editor. Diga para usar um comando de editor que modifique o crontab como você deseja. O comando editor é executado como um fragmento de shell com o nome de um arquivo temporário anexado.

unset VISUAL
EDITOR='update_crontab () {
  set -e
  new=$(mktemp)
  if <"$1" grep -v "^#" | grep -w do_stuff; then
    # Remove existing entries containing do_stuff
    grep -v -w do_stuff "$1" >"$new"
  else
    cp "$1" "$new"
  fi
  # Add the new entry
  echo "1 2 3 4 5 do_stuff --new-options" >>"$new"
  mv "$new" "$1"
}
update_crontab' crontab -e

Essa abordagem é mais confiável do que a crontab -l | … | crontab - nativa porque esta é vulnerável a uma condição de corrida se o crontab for editado simultaneamente: as modificações feitas entre a chamada para crontab -l e a chamada para crontab - seriam desfeitas.

    
por 25.07.2016 / 02:17
0

Esta é uma adaptação do que phillip-zyan-k-lee-stockmann oferecido, com base em seu código "Melhor ideia até agora".

Minhas alterações do seu (excelente e útil trecho) são basicamente:

  • Regex para não apenas o nome do comando, mas também a entrada inteira, incluindo as strings de tempo. Dessa forma, ele poderia suportar a adição de um comando, mesmo que houvesse comandos nomeados com o mesmo nome ou sobrepostos em outras entradas. (Ainda não adicionará o mesmo comando no mesmo agendamento duas vezes.)
  • Um pouco de registro
  • eu mudei (e nomeei) o meu para por hora por várias razões; fácil de ajustar de volta por sintaxe crontab

E aqui está o meu código para o que chamei de crontab-add-hourly.sh :

#!/bin/bash

# PURPOSE:
# To allow simple, programmatic addition of commands/entries into the crontab (if not already present)

cmd=$1
entry="0 * * * * $cmd"
printf "we want to add this entry:\n$entry\n\n" 
escapedEntry=$(printf '%s\n' "$entry" | sed 's:[][\/.^$*]:\&:g') #from: https://unix.stackexchange.com/a/129063/320236
printf "but first we'll see if it's already in there using this regex pattern:\n$escapedEntry\n\n"

if [[ $(crontab -l | egrep -v '^(#|$)' | grep -q "$escapedEntry"; echo $?) == 1 ]] # from: https://unix.stackexchange.com/a/297377/320236
then
    printf "all clear; pattern was not already present; adding command to crontab hourly:\n$cmd\n\n"
    (crontab -l ; printf "$entry\n\n") | crontab -
else
    printf "pattern already present; no action taken\n\n"
fi

Exemplo de uso e saída:

$ ./crontab-add-hourly.sh my-script.bash

we want to add this entry:
0 * * * * my-script.bash

but first we'll see if it's already in there using this regex pattern:
0 \* \* \* \* my-script\.bash

all clear; pattern was not already present; adding command to crontab hourly:
my-script.bash
    
por 09.11.2018 / 19:52