Aggiungi qualcosa a crontab a livello di codice (su ssh)


13

Ho uno script di distribuzione, deve aggiungere qualcosa a un utente crontab(attivare uno script che pulisce i registri ogni XXX giorni), tuttavia questo deve essere fatto solo durante la prima distribuzione o quando deve essere aggiornato.

(Posso correre xxx.py deploy envo xxx.py update env)

quindi devo fare questo:

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

Non vedo come aggiungere / controllare / rimuovere qualcosa crontabsenza usare crontab -eo modificare il crontabfile (scaricarlo, riscriverlo, ricaricarlo)

PS: questo è un cronjob specifico dell'utente, "webadmin" lo farà e non dovrebbe usare sudo per farlo.


1
Deve essere in un crontab specifico dell'utente? La maggior parte dei lavori cron preconfezionati vanno in una delle directory /etc/cron.*.
un CVn

CentOS ha /etc/cron.d? In tal caso, inserisci il tuo script usando un nome univoco per la tua applicazione
roaima,

sì, è specifico dell'utente. Non riesco ad aggiungerlo a /etc/cron.d perché è un file root, quindi solo il lavoro di root è presente all'interno (potrei sudo ma che una cattiva pratica mi è stato detto)
sliders_alpha

1
come i /etc/crontabfile in /etc/cron.d/hanno un campo aggiuntivo per il nome utente, immediatamente dopo le specifiche del programma. es * * * * * username /path/to/script. Vedi man 5 crontabe cerca SYSTEM CRON.
Cas

Risposte:


15

la mia migliore idea finora

per prima cosa controlla se il contenuto corrisponde a quello che dovrebbe essere lì dentro e aggiorna solo se non lo fa:

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

ma questo diventa abbastanza complicato da creare uno script separato attorno a quell'attività cron.

altre idee

potresti inviare la stringa tramite stdin a crontab (attenzione, questo cancella tutte le voci precedenti di crontab):

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

questo dovrebbe funzionare anche attraverso ssh:

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

se si desidera aggiungere al file è possibile utilizzare questo:

# 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 -"

dipende: hai bisogno di quello che sarebbe stato lì? :)
Phillip -Zyan K Lee- Stockmann

awww ... non funziona come root? ... lo riscriverò ...
Phillip -Zyan K Lee- Stockmann

eh, mi piace quello: D
sliders_alpha,

Ho avuto due problemi con questa soluzione: 1) echo '*...espanso *in un elenco di file. 2) le terminazioni di riga nel crontab sono state eliminate.
Heath Raftery,

Sono stato in grado di risolvere questi problemi: 1) passare a echo "*...e 2) rimuovere echo $dall'inizio della riga.
Heath Raftery,

3

Per la cronaca, suggerirò di usare /etc/cron.d/. Solo root può scrivere file qui, ma le voci possono essere eseguite come qualsiasi utente (senza necessità di sudo).

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

Questo può essere applicato più volte, aggiornando il webadmin.cronfile locale come necessario prima di copiarlo.

Puoi persino rimuovere il provisioning:

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

Si noti che in molti casi non è possibile fornire la password di root per i comandi scp/ ssh. Invece è necessario aver impostato i certificati di chiave pubblica / privata. Inoltre, implicitamente l'account locale (qualunque esso sia) avrà pieno accesso root al server remoto. Al momento non è chiaro se ciò rappresenterebbe un ostacolo per lo scenario specifico.


È il mio server client, non riesco ad accedere come root, posso accederci MA, se lo faccio mi uccideranno. Questo è un lavoro di webadlmin quindi dovrebbe essere solo nelle cose di webadmin, questo è quello che mi ha detto l'amministratore di sistema.
sliders_alpha,

@sliders_alpha il lavoro viene eseguito solo come webadmin. È il provisioning che richiede l'equivalenza di root. Tuttavia, cercherò anche una soluzione non root.
roaima,

1
+1. /etc/cron.d/esiste proprio per questo scopo - in modo che pacchetti / distribuzioni possano semplicemente rilasciare un file crontab qui.
Cas

3

Consiglio vivamente di utilizzare Ansible * per questo invece di farne uno tuo. O Puppet o Chef - ma Ansible è adatto per script di distribuzione a infrastruttura zero come questo.

Questo perché ci sono già moduli pensati per risolvere problemi come questo e gli strumenti di gestione della configurazione hanno l' idempotenza come obiettivo di progettazione di base - questa è la proprietà di cambiare solo quando è necessario anche se lo si esegue di nuovo accidentalmente (o intenzionalmente).

In particolare, il modulo cron di Ansible può modificare i crontab degli utenti. Come bonus, se vuoi adattarti in seguito per usare i crontab di sistema, sarà una modifica molto semplice piuttosto che una riscrittura.


* disclaimer: lavoro per Red Hat e Ansible è un progetto sponsorizzato da Red Hat.


Sì, il fatto è che non sapevo di ansible 2 mesi fa, e ora abbiamo un enorme script deployer in pitone (ma è MAGNIFICIENTE, leggibile, mantenibile;;)) La prossima volta, userò ansible ma adesso il ritorno è impossibile (soldi soldi soldi)
sliders_alpha

1

Se si desidera aggiungere un processo cron tramite l'account di destinazione, eseguire crontab -e. Questo comando passa il crontab attraverso un editor. Digli di usare un comando editor che modifica il crontab come desideri. Il comando editor viene eseguito come frammento di shell con il nome di un file temporaneo aggiunto.

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

Questo approccio è più affidabile del nativo crontab -l | … | crontab -perché questo è vulnerabile a una race condition se il crontab viene modificato contemporaneamente: le modifiche apportate tra la chiamata a crontab -le la chiamata a crontab -sarebbero annullate.


1

Questo è un adattamento di ciò che @ phillip-zyan-k-lee-stockmann ha offerto, basato sul suo codice "La migliore idea finora".

Le mie modifiche dal suo (snippet eccellente e utile) sono sostanzialmente:

  • Regex non solo per il nome del comando, ma anche per l'intera voce, comprese le stringhe temporali. In questo modo potrebbe supportare l'aggiunta di un comando anche se ci sono comandi con lo stesso nome o sovrapposti in altre voci. (Non aggiungerà due volte lo stesso comando nella stessa pianificazione.)
  • Un po 'di registrazione
  • Ho cambiato (e nominato) il mio ogni ora per vari motivi; facile da regolare indietro per sintassi crontab

E quindi ecco il mio codice per quello che ho chiamato 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

Esempio di utilizzo e output:

$ ./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

0

TL; DR: funziona davvero, testato in Bash 4.4.

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

Come notato nei commenti della risposta di @Phillip -Zyan K Lee- Stockmann, quella soluzione si espande *in tutti i file nella directory corrente. Non sono riuscito a far funzionare il suggerimento dei commenti. set -f disabilita l'espansione jolly, consultare https://stackoverflow.com/a/11456496/915441 .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.