jobscheduler 1.13.11からjs7 2.3.0への手動移行

# 初めに
筆者は自宅で物理3台+仮想1台の構成のサーバーを運用しています。仮想1台がsos jobscheduler/js7専用で、他の3台にエージェントを導入し、毎時・日次・週次のジョブを流しています。

従来jobscheduler 1.13.11で運用していましたが、js7 2.3.0に移行しました。jobschedulerでは、jobstreamで一連のジョブを実行していましたが、js7ではjobstreamが実装されないため、手作業でjobstreamをjs7のワークフローに移行しました。

js7 2.4でjobschedulerからjs7への移行ツールが提供される予定です。しかし、以下の理由でおそらく移行ツールでは移行できないだろうと判断し、手動で移行することにしました。

- ジョブで、おそらくjobschedulerが想定していない使い方をしている。
- jobstreamで、おそらくjobschedulerが想定していない使い方をしている。
# ジョブの要件
jobschedulerのジョブの要件は、以下のように定めました。
1. jobscheduler内で定義した各サーバ共通のスクリプトを使いたい。jobscheduler外で各サーバに共通のスクリプトを配信することは避けたい。
1. 日次ジョブを終了後に週次ジョブが実行されるようにしたい。
1. 毎時ジョブは日次ジョブ・週次ジョブ実行中には走らないようにしたい。
# jobschedulerでの実装
以下のようにしてジョブの要件は実装しました。
## 共通スクリプト
ジョブのconfig/liveフォルダに共通スクリプトのファイルを置き、共通スクリプトを使用するジョブでインクルードするようにしました。共通スクリプトファイルの内容は以下のようにしました。
~~~
#!/bin/bash
cat << END | tee /tmp/common.inc
function backupthis {
    local snap=\${1}-snap
    snapandmount vg0 \$1 \$snap \$mntp
...
}
...
END
~~~
### 各行の説明
~~~
#!/bin/bash
~~~
スクリプトがbashで記述されていることのを指定します。
~~~
cat << END | tee /tmp/common.inc
~~~
インクルードしたファイルの内容をジョブを実行するサーバーの/tmp/common.incにコピーします。
~~~
function backupthis {
~~~
各サーバーで共通で使うスクリプトをbashのfunctionとして記述します。各サーバで共通で使うスクリプトの分だけ記述します。
~~~
    local snap=\${1}-snap
    snapandmount vg0 \$1 \$snap \$mntp
~~~
インクルードしたファイルを/tmp/common.incにコピーする際に\\$変数名は展開されて、コピーしたファイルからは\\$変数名の記述が消えます。これを避けるため\\$は\\でエスケープします。
## 週次ジョブは日次ジョブの終了後に実行
### 週次ジョブの実装
週次ジョブと日次ジョブは同時刻に開始するようstarterに実行時間を設定しました。週次ジョブは週末のみ、日次ジョブは毎日実行します。

週次ジョブはその先頭にダミーのジョブを置きました。その次に週次ジョブの置き、In Conditionは以下のようにして日次ジョブの終了を待つようにしました。
~~~
   ダミージョブのイベント and グローバルの日次ジョブの終了イベント
~~~
このようにすることで、週次ジョブは先頭で日次ジョブの終了を待ちます。
### 日次ジョブの実装
日次ジョブは毎日実行します。その最後のジョブのOut conditionでグローバルの日次ジョブ終了のイベントを生成するようにしました。このようにすることで前述のように日次ジョブ終了後に週次ジョブが走ります。
## 日次ジョブ・週次ジョブ実行中は毎時ジョブが走らない
### 日次ジョブの実装
毎時ジョブの先頭と最後にダミージョブを置きました。
![Qiita図面1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505283/a702ecfd-0236-d546-0d58-34f8dc6e2204.jpeg)
毎時ジョブの真の先頭のIn conditionを以下のようにして日次ジョブ・週次ジョブが実行中は毎時ジョブが走らないようにしてあります。
~~~
   先頭のダミージョブのイベント and グローバルの毎時ジョブ開始のイベント
~~~
グローバルの毎時ジョブ開始のイベントが存在しないタイミングで開始した毎時ジョブを終了されるためもう一つ別のダミージョブを置きそのIn contitionは以下のようにしてあります。
~~~
   先頭のダミージョブのイベント and not グローバルの毎時ジョブ開始のイベント
~~~
このようにすることでグローバルの毎時ジョブ開始のイベントが存在しないタイミングではこちらのパスが走ます。日次ジョブの最後のダミージョブのIn conditionは以下のようにすることで、どちらのパスが走っても実行されて、日次ジョブは終了します。
~~~
   ダミージョブのイベント or 毎時ジョブのイベント
~~~
毎時ジョブを終了させておかないと、毎時ジョブが実行待ちの順次待ち状態になるため、グローバルの毎時ジョブ開始のイベントが生成されたタイミングで、待ち状態の毎時ジョブが走り出すことになります。
### 日次ジョブ・週次ジョブの実装
日次ジョブはのStarterは月曜日～土曜日と日曜日の二つを使っています。
![Qiita図面2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505283/f7e15674-d2c1-7b22-a12a-ccf8a73f0d15.jpeg)
月～土のダミージョブのIn conditionは以下のようにしています。
~~~
   日次ジョブのイベント and not 日のダミージョブ1のイベント
~~~
このようにすることで月～土のダミージョブは月曜日～土曜日にのみ実行されます。Out conditionではグローバルの毎時ジョブ開始イベントを生成します。

日のダミージョブのIn conditionは以下のようにしています。
~~~
   日次ジョブのイベント and 日のダミージョブ1のイベント
~~~
このようにすることで日のダミージョブは日曜日にのみ実行されます。Out conditionではグローバルの毎時ジョブ開始イベントを生成しません。このようにすることで、日曜日には日ジョブ終了時に毎時ジョブが走り出すことはありません。
# js7での実装
## 共通スクリプト
js7のワークフローにはScript Includesと呼ぶスクリプトの共通部分を定義する機能があります。ワークフローでワークフロー内でインクルードするScript Includesを指定します。

ジョブの中では以下のようにしてインクルードします。
~~~
   #!/bin/bash
   ##!include インクルードするJob Resource名
~~~
Script Includesでのスクリプトは、\\$記号を\\記号でエスケープする必要はなく通常の記述となります。
## 週次ジョブは日次ジョブの終了後に実行
js7にはjobstreamがありませんので、ワークフローで同等の機能を実装しました。
### 週次ジョブの実装
週次のワークフローは日次のワークフローとと同時に実行を開始します。最初のステップで週次ジョブ開始のNoticeを待つようにしました。
### 日次ジョブの実装
日次ワークフローは最後のステップで週次ジョブ開始のNoticeを生成します。これで週次ワークフローが実行を中断していれば実行が再開となります。週次ワークフローが実行中でなければ、週次ジョブ開始のNotice生成だけとなります。
## 日次ジョブ・週次ジョブ実行中は毎時ジョブが走らない
### 毎時ジョブの実装
毎時ワークフローの先頭で毎時ジョブ開始ファイルの有無をチェックするジョブを置きます。存在すれば戻り値を1にします。
![Qiita図面3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505283/627b49ad-38da-0f4d-5ac9-4ac37434abb6.jpeg)
ifで戻り値が1、つまり毎時ジョブ開始ファイルが存在すれば毎時ジョブを実行します。しなければ毎時ジョブが実質実行されずに終了します。
### 日次ジョブ・週次ジョブの実装
日次ワークフローの最後に月曜日～土曜日なら毎時ジョブ開始ファイルを生成するジョブを置きまました。月曜日～土曜日には日次ワークフローで毎時ジョブ開始ファイルが生成され日曜日には生成されません。

週次ワークフローの最後に毎時ジョブ開始ファイルを生成するジョブを置きます。

このようにすることで日次ワークフローと週次ワークフロー実行中は毎時ジョブ開始ファイルが存在しないため、毎時ワークフローは実質実行されません。
# おわりに
jobscheduler 1.13では記述が不自然だった共通スクリプトや日次ジョブ・週次ジョブ実行中は毎時ジョブが走らない要件の実装が、js7では自然な形となり可読性やメンテナンス性が向上しました。