web-dev-qa-db-ja.com

プログラムで(sshを介して)何かをcrontabに追加する

私は展開スクリプトを持っています。ユーザー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 -eを使用したり、crontabファイルを編集したりせずにcrontabに何かを追加/チェック/削除する方法がわかりません(ダウンロード、再書き込み、再アップロード)

PS:これはユーザー固有のcronjobであり、「webadmin」が実行する予定であり、Sudoを使用して実行するべきではありません。

13
sliders_alpha

これまでの私の最高のアイデア

コンテンツがそこにあるべきものと一致するかどうかを最初にチェックし、一致しない場合にのみ更新するには:

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

記録として、/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

多くの場合、scp/sshコマンドにrootのパスワードを提供できないことに注意してください。代わりに、公開鍵/秘密鍵証明書を設定する必要があります。また、暗黙的にローカルアカウント(それが何であれ)は、リモートサーバーへの完全なrootアクセス権を持ちます。それがあなたの特定のシナリオのショーストッパーになるかどうかは現時点では不明です。

3
roaima

自分でロールするのではなく、Ansible *を使用することを強くお勧めします。またはPuppetまたはChef —しかし、Ansibleは、このようなインフラストラクチャなしのデプロイスクリプトに適しています。

これは、このような問題を解決するためのモジュールがすでにあり、構成管理ツールに基本的な設計目標として idempotence があるためです。これは、誤って(または意図的に)必要な場合にのみ変更できるという特性です)もう一度実行します。

特に、Ansibleの cronモジュール は、ユーザーのcrontabを変更できます。おまけとして、後でシステムのcrontabを使用するように調整する場合は、書き換えではなく非常に簡単なTweakになります。


*免責事項:私はRed Hatで働いており、AnsibleはRed Hatがスポンサーとなっているプロジェクトです。

3
mattdm

ターゲットアカウントを介して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 -の呼び出しの間に行われた変更が元に戻されます。

これは、彼の「これまでのところ最高のアイデア」コードに基づいて提供された @ phillip-zyan-k-lee-stockmann の適応です。

彼の(優れた役立つスニペット)からの私の変更は、基本的には次のとおりです。

  • コマンド名だけでなく、時間文字列を含むエントリ全体の正規表現。これにより、他のエントリに同じ名前のコマンドまたは重複する名前のコマンドがある場合でも、コマンドの追加をサポートできます。 (同じコマンドを同じスケジュールで2回追加することはありません。)
  • 少しロギング
  • 私はさまざまな理由で鉱山を時間単位に切り替えました(そして名前を付けました)。 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
1
user1417853

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 を参照してください。

0