Tips: Ansibleにおけるwhile, until処理


Ansibleによる単一のタスクに対するループ(until)

-
  until: r.stdout|int <= 0
  shell: |
    NEW=$(( $(cat NUM) - 1 ))
    echo $NEW > NUM
    cat NUM
  register: r
  retries: 10
  delay: 0

この例では、shellタスクのstdoutが0以下になるまで、もしくは最大でretries:指定の10回まで処理を繰り返します。
終了条件には、shellモジュールならばコマンドのstdout, stderr, rcなど、register変数に設定される値が使用可能です。
retries:は最大リトライ回数で、省略可能ですがデフォルトは3回とかなり少ない為、余裕を持った指定が必要です。
delay:はループの待ち時間(秒)でデフォルトは1(秒)です。
breakは、until:の条件を満たす事で対応可能です。例えば上の例の場合、echo 0; exit などとすればこのタスクを抜ける事ができます。

コマンド実行結果を判断に使用する為、until:の条件を満たしていても最初の1回は実行されます。

NUM初期値が5の場合の出力例

TASK [shell] *******************************************************************
FAILED - RETRYING: command (10 retries left).
FAILED - RETRYING: command (9 retries left).
FAILED - RETRYING: command (8 retries left).
FAILED - RETRYING: command (7 retries left).
changed: [localhost]

5回実行。
untilの条件を満たす事ができなかった回はFAILEDと表示される。5回目に成功して、changed: が出力されている。
retries:の回数内で成功しなかった場合にはtaskそのものがfailedとなる。
実行後のNUMは0。

NUM初期値が1の場合の出力例

TASK [shell] *******************************************************************
changed: [localhost]

1回実行。
実行後のNUMは0。

NUM初期値が0の場合の出力例

TASK [shell] *******************************************************************
changed: [localhost]

untilの為、1回は実行されてしまう。
実行後のNUMは-1。

Ansibleによる単一のタスクに対するループ(while)

通常のプログラミング言語におけるwhileループ、即ち、初回実行に関しても条件による実施判断を行わせるには、例えば以下の様に、事前に情報収拾を行い、when:により判断させる対応が可能でしょう。

-
  shell: |
    cat ./NUM
  register: r0
  changed_when: false

-
  when: not r0.stdout|int <= 0
  until:    r1.stdout|int <= 0
  shell: |
    NEW=$(( $(cat ./NUM) - 1 ))
    echo $NEW > ./NUM
    cat ./NUM
  register: r1
  retries: 10
  delay: 0

この例では判り易さの為にr0, r1とregister変数を分けていますが、上書きされるので同じ変数を再利用可能です。

NUM初期値が0(もしくは負)の場合の出力例

TASK [shell] *******************************************************************
skipping: [localhost]

0回実行(skip)
実行後のNUMは変更なし。

ブロックに対するループ

untilやloop:などは個別のタスクに対してのみ指定可能であり、taskを集めたblock:に対して実施できないという制約があります。(エラーとなります。)
また、個別のタスクに複数のループを指定できない事から、そのままでは任意の多重ループに関しても実現できません。
この状況を回避するには、以下の様な対応が可能です。

  • 別ファイルに分けたロジックを動的に読み込むinclude_tasks:などに対してループを行う

静的に読み込むimport_tasksなどは使用できない為、制約などがありうる事に注意が必要です。

公式: Tradeoffs and Pitfalls Between Includes and Imports