Tambahkan sesuatu ke crontab secara terprogram (lebih dari ssh)

13

Saya memiliki skrip penerapan, harus menambahkan sesuatu ke pengguna crontab(memicu skrip yang membersihkan log setiap XXX hari), namun ini hanya boleh dilakukan selama penerapan pertama, atau saat perlu diperbarui.

(Saya bisa lari xxx.py deploy envatau xxx.py update env)

jadi saya harus melakukan ini:

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

Saya tidak melihat cara menambah / memeriksa / menghapus sesuatu crontabtanpa menggunakan crontab -eatau mengedit crontabfile (unduh, tulis ulang, unggah kembali)

PS: ini adalah cronjob khusus pengguna, "webadmin" akan melakukannya dan ia tidak boleh menggunakan sudo untuk melakukannya.

sliders_alpha
sumber
1
Apakah harus menggunakan crontab khusus pengguna? Sebagian besar pekerjaan cron yang telah dipaket masuk ke salah satu direktori /etc/cron.*.
CVn
Apakah CentOS punya /etc/cron.d? Jika demikian, letakkan skrip Anda di sana menggunakan nama yang unik untuk aplikasi Anda
roaima
ya itu spesifik pengguna. Saya tidak bisa menambahkannya ke /etc/cron.d karena ini adalah file root, sehingga hanya pekerjaan root yang diubah di dalam (saya bisa sudo tetapi itu praktik buruk yang telah saya sampaikan)
sliders_alpha
1
sama seperti /etc/crontab, file dalam /etc/cron.d/memiliki bidang tambahan untuk nama pengguna, segera setelah spesifikasi jadwal. mis * * * * * username /path/to/script. Lihat man 5 crontabdan cari SYSTEM CRON.
cas

Jawaban:

15

ide terbaik saya sejauh ini

untuk memeriksa dulu apakah konten cocok dengan apa yang seharusnya ada di sana dan hanya memperbarui jika tidak:

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

tetapi ini menjadi cukup rumit untuk membangun skrip terpisah di sekitar tugas cron itu.

ide lain

Anda dapat mengirim string melalui stdin ke crontab (berhati-hatilah, ini menghapus semua entri crontab sebelumnya):

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

ini bahkan harus bekerja melalui ssh:

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

jika Anda ingin menambahkan file Anda dapat menggunakan ini:

# 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 -"
Phillip -Zyan K Lee- Stockmann
sumber
itu tergantung: apakah Anda memerlukan apa yang ada di sana? :)
Phillip -Zyan K Lee- Stockmann
awww ... tidak berjalan sebagai root? ... Saya akan menulis ulang ...
Phillip -Zyan K Lee- Stockmann
eh, saya suka itu: D
sliders_alpha
Saya punya dua masalah dengan solusi ini: 1) echo '*...memperluas *ke daftar file. 2) ujung baris di crontab terhapus.
Heath Raftery
Saya dapat memperbaiki masalah ini dengan: 1) ubah menjadi echo "*...dan 2) hapus echo $dari awal baris.
Heath Raftery
3

Sebagai catatan saya akan menyarankan menggunakan /etc/cron.d/. Hanya root yang dapat menulis file di sini tetapi entri dapat dijalankan sebagai pengguna mana pun (tanpa perlu sudo).

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

Ini dapat diterapkan beberapa kali, memperbarui webadmin.cronfile lokal seperlunya sebelum menyalinnya.

Anda bahkan dapat menghapus ketentuan:

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

Perhatikan bahwa dalam banyak kasus Anda tidak dapat memberikan kata sandi root untuk perintah scp/ ssh. Alih-alih, Anda harus menyiapkan sertifikat kunci publik / pribadi. Juga, dengan implikasi akun lokal (apa pun itu) akan memiliki akses root penuh ke server jarak jauh. Tidak jelas pada saat ini apakah itu akan menjadi show-stopper untuk skenario spesifik Anda.

roaima
sumber
Ini server klien saya, saya tidak bisa login sebagai root, saya bisa sudo ke dalamnya NAMUN, jika saya melakukannya mereka akan membunuh saya. Ini adalah pekerjaan webadlmin jadi seharusnya hanya dalam hal webadmin, itulah yang dikatakan sysadmin kepada saya.
sliders_alpha
@sliders_alpha pekerjaan hanya berjalan sebagai webadmin. Provisi yang membutuhkan kesetaraan root. Namun, saya akan mencari solusi non-root juga.
roaima
1
+1. /etc/cron.d/ada persis untuk tujuan ini - sehingga paket / penyebaran hanya bisa meletakkan file crontab di sini.
cas
3

Saya sangat merekomendasikan menggunakan Ansible * untuk ini daripada menggulirkan sendiri. Atau Boneka atau Koki - tetapi Ansible sangat cocok untuk skrip penerapan tanpa infrastruktur seperti ini.

Itu karena sudah ada modul yang dimaksudkan untuk menyelesaikan masalah seperti ini, dan alat-alat manajemen konfigurasi telah memiliki idempotensi sebagai tujuan desain dasar - itu adalah properti hanya berubah ketika perlu bahkan jika Anda secara tidak sengaja (atau sengaja) menjalankannya lagi.

Secara khusus, modul cron Ansible dapat memodifikasi crontab pengguna. Sebagai bonus, jika Anda ingin menyesuaikan kemudian menggunakan crontab sistem, itu akan menjadi tweak yang sangat mudah daripada menulis ulang.


* Penafian: Saya bekerja untuk Red Hat, dan Ansible adalah proyek yang disponsori Red Hat.

mattdm
sumber
Yup, masalahnya, saya tidak tahu tentang kemungkinan 2 bulan yang lalu, dan sekarang kami memiliki skrip python deployer besar (tapi dia MAGNIFICIENT, dapat dibaca, dapat dikelola,;)) Lain kali, saya akan menggunakan yang mungkin tetapi sekarang akan pergi kembali tidak mungkin (uang uang uang)
sliders_alpha
1

Jika Anda ingin menambahkan pekerjaan cron melalui akun target, jalankan crontab -e. Perintah ini melewati crontab melalui editor. Katakan untuk menggunakan perintah editor yang memodifikasi crontab sesuai keinginan Anda. Perintah editor dieksekusi sebagai potongan shell dengan nama file sementara ditambahkan.

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

Pendekatan ini lebih dapat diandalkan daripada yang asli crontab -l | … | crontab -karena yang ini rentan terhadap kondisi ras jika crontab diedit secara bersamaan: modifikasi yang dibuat antara panggilan ke crontab -ldan panggilan ke crontab -akan dibatalkan.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
1

Ini adalah adaptasi dari apa yang ditawarkan @ phillip-zyan-k-lee-stockmann , berdasarkan kode "Ide terbaik sejauh ini".

Perubahan saya dari cuplikannya (sangat baik dan bermanfaat) pada dasarnya:

  • Regex untuk tidak hanya nama perintah, tetapi juga seluruh entri termasuk string waktu. Dengan cara itu bisa mendukung menambahkan perintah bahkan jika ada perintah yang sama-nama atau tumpang tindih-nama di entri lain. (Masih tidak akan menambahkan perintah yang sama pada jadwal yang sama dua kali.)
  • Sedikit penebangan
  • Saya mengganti (dan memberi nama) milik saya menjadi setiap jam karena berbagai alasan; mudah untuk menyesuaikannya kembali per sintaks crontab

Dan inilah kode saya untuk apa yang saya sebut 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

Contoh penggunaan dan 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
pengguna1417853
sumber
0

TL; DR: Ini benar-benar berfungsi, diuji dalam 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

Sebagaimana dicatat dalam komentar jawaban @Phillip -Zyan K Lee- Stockmann, solusi itu mengembang *ke semua file di direktori saat ini. Saya tidak bisa mendapatkan saran komentar untuk bekerja. set -f menonaktifkan ekspansi wildcard, lihat https://stackoverflow.com/a/11456496/915441 .

Yngvar Kristiansen
sumber