Добавить что-то в crontab программно (через ssh)

13

У меня есть сценарий развертывания, он должен что-то добавить пользователю crontab(запускать сценарий, который очищает журналы каждые XXX дней), однако это необходимо делать только во время первого развертывания или когда его необходимо обновить.

(Я могу бежать xxx.py deploy envили xxx.py update env)

поэтому я должен сделать это:

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

Я не вижу, как добавить / проверить / удалить что-либо crontabбез использования crontab -eили редактирования crontabфайла (загрузить его, переписать, повторно загрузить)

PS: это специфический для пользователя cronjob, "webadmin" собирается это сделать, и ему не следует использовать sudo для этого.

sliders_alpha
источник
1
Должен ли он быть в пользовательском crontab? Большинство предварительно упакованных заданий cron попадают в один из каталогов /etc/cron.*.
CVn
Есть ли CentOS /etc/cron.d? Если это так, поместите ваш сценарий туда, используя уникальное имя для вашего приложения
roaima
да, это зависит от пользователя. Я не могу добавить его в /etc/cron.d, потому что это корневой файл, поэтому только внутренняя работа разрешена (я могу судить, но это плохая практика, как мне сказали)
sliders_alpha
1
так же, как /etc/crontabфайлы в /etc/cron.d/имеют дополнительное поле для имени пользователя, сразу после спецификации расписания. например * * * * * username /path/to/script. Смотрите man 5 crontabи ищите SYSTEM CRON.
КАС
Смотрите также stackoverflow.com/questions/610839/...
rogerdpack

Ответы:

15

моя лучшая идея

сначала проверить, соответствует ли содержимое тому, что должно быть там, и обновить, только если оно не соответствует:

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

но это становится достаточно сложным, чтобы создать отдельный скрипт для этой задачи cron.

другие идеи

Вы можете отправить строку через stdin в crontab (будьте осторожны, это удалит все предыдущие записи в crontab):

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

это должно работать даже через ssh:

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

если вы хотите добавить файл, вы можете использовать это:

# 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 -"
Филипп-Зьян К Ли-Стокманн
источник
это зависит: вам нужно то, что было бы там? :)
Филипп-Зьян К Ли - Стокманн
аууу ... не работает как root? ... Я
перепишу
эх, мне это нравится: D
sliders_alpha
У меня было две проблемы с этим решением: 1) echo '*...расширил *список файлов. 2) окончания строк в crontab были удалены.
Хит
Я смог исправить эти проблемы следующим образом: 1) изменить echo "*...и 2) удалить echo $из начала строки.
Хит
3

Для записи я собираюсь предложить использовать /etc/cron.d/. Только root может записывать файлы здесь, но записи могут быть запущены как любой пользователь (без необходимости sudo).

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

Это может быть применено несколько раз, обновляя локальный webadmin.cronфайл по мере необходимости перед его копированием.

Вы даже можете удалить предоставление:

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

Обратите внимание, что во многих случаях вы не можете предоставить пароль пользователя root для команд scp/ ssh. Вместо этого вам нужно настроить сертификаты открытого / закрытого ключа. Также подразумевается, что локальная учетная запись (какой бы она ни была) будет иметь полный root-доступ к удаленному серверу. На данный момент неясно, будет ли это шоу-стопором для вашего конкретного сценария.

roaima
источник
Это мой клиентский сервер, я не могу войти в систему как root, я могу войти в него, НО, если я это сделаю, меня убьют. Это работа webadlmin, поэтому она должна быть только в материалах webadmin, это то, что сказал мне сисадмин.
sliders_alpha
@sliders_alpha задание работает только как webadmin. Это обеспечение требует корневой эквивалентности. Однако я тоже поищу некорневое решение.
Ройма
1
+1. /etc/cron.d/существует именно для этой цели - поэтому пакеты / развертывания могут просто вставить сюда файл crontab.
Cas
3

Я настоятельно рекомендую использовать для этого Ansible *, а не использовать свой собственный. Или Puppet или Chef - но Ansible хорошо подходит для таких сценариев развертывания без инфраструктуры, как этот.

Это потому, что уже есть модули, предназначенные для решения подобных проблем, и инструменты управления конфигурациями имеют идемпотентность в качестве основной цели проектирования - это свойство изменять только тогда, когда это необходимо, даже если вы случайно (или намеренно) запустите его снова.

В частности, модуль cron Ansible может изменять пользовательские crontabs. В качестве бонуса, если вы захотите позже использовать системные crontabs, это будет очень просто, а не переписывать.


* Отказ от ответственности: я работаю в Red Hat, а Ansible - это проект, спонсируемый Red Hat.

mattdm
источник
Да, дело в том, что я не знал об ANSIBLE 2 месяца назад, и теперь у нас есть массивный скрипт для развертывания Python (но он МАГНИТНЫЙ, читаемый, обслуживаемый,;)) В следующий раз я буду использовать ANSIBLE, но сейчас собираюсь вернуться невозможно (деньги, деньги, деньги)
sliders_alpha
1

Если вы хотите добавить задание cron через целевую учетную запись, запустите crontab -e. Эта команда передает crontab через редактор. Скажите ему использовать команду редактора, которая изменяет crontab по вашему желанию. Команда редактора выполняется в виде фрагмента оболочки с добавлением имени временного файла.

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

Этот подход более надежен, чем собственный, crontab -l | … | crontab -потому что он уязвим для состояния гонки, если crontab редактируется одновременно: изменения, сделанные между вызовом crontab -lи вызовом crontab -, будут отменены.

Жиль "ТАК - прекрати быть злым"
источник
1

Это адаптация того, что предложил @ phillip-zyan-k-lee-stockmann , на основе его кода «Лучшая идея на данный момент».

Мои изменения из его (отличный и полезный фрагмент) в основном:

  • Regex для не только имени команды, но и всей записи, включая строки времени. Таким образом, он может поддерживать добавление команды, даже если в других записях есть команды с одинаковыми или перекрывающимися именами. (Он все равно не добавит одну и ту же команду в одно и то же расписание дважды.)
  • Немного регистрации
  • Я переключил (и назвал) мой на почасовой по различным причинам; легко настроить обратно в соответствии с синтаксисом crontab

И вот мой код для того, что я назвал 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

Пример использования и вывод:

$ ./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
user1417853
источник
0

TL; DR: это на самом деле работает, протестировано в 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

Как отмечено в комментариях @Phillip -Zyan K Lee- Stockmann, это решение распространяется *на все файлы в текущем каталоге. Я не мог заставить предложение комментариев работать. set -f отключает расширение по шаблону, см. https://stackoverflow.com/a/11456496/915441 .

Ингвар Кристиансен
источник