条件と繰り返しで分岐を圧縮する
目標
コピー・ペーストで増えていたタスクをデータと繰り返しにまとめ、条件で項目をふるい分けられるようになります。
なぜ重要なのか
ほとんど同じタスクが複数あると、そのうちの1つだけが違うというミスが必ず生じ、コードを読んでも見つけにくいです。タスクを1つに減らせば、ミスする場所も1つになり、データは表のように見えるので、抜けたマスが目立ちます。繰り返しを使うとき、実務でよく引っかかるのは3つです。ログの露出: ディクショナリをそのまま回すと、その中の値がすべてログに出力されるので、loop_control.labelが必要です。冪等性: 繰り返しが10回動けば、非冪等の被害も10倍です。組み合わせ爆発: 2つのリストの積は、すぐに大きくなります。そして、untilで何かを待つときは、「この時間内にできなければ本当に問題だ」という判断を、リトライ回数に込めてください。
ステップ
/root/ans/loops/site.ymlでloopを使い、/root/ans/loops/simple/の下にalpha、beta、gammaディレクトリを作成してください。タスクは1つである必要があります。/opt/lab/fixtures/ansible/users.ymlのapp_usersを読み込み、各項目のdirをmodeの権限で作成してください。/root/ans/loops/deploy(0750)、/root/ans/loops/metrics(0755)、/root/ans/loops/backup(0700)です。- 同じ繰り返しに
whenを付けて、0755より厳しい項目のディレクトリにだけPRIVILEGEDファイルを残してください。/root/ans/loops/deploy/PRIVILEGEDと/root/ans/loops/backup/PRIVILEGEDは作られ、/root/ans/loops/metrics/PRIVILEGEDは作られてはいけません。 loop_controlのlabelでログを整理し、実行出力を/root/ans/loops/out/run.txtに保存してください。ログにitem=deployの形式の省略ラベルが見え、ディクショナリ全体が見えてはいけません。until/retries/delayを使った待機タスクを作成し、成功した結果を/root/ans/loops/out/ready.txtに、readyという内容で残してください。- 環境(
dev、stage、prod) × コンポーネント(app、worker)の組み合わせで、/root/ans/loops/matrix/<환경>-<컴포넌트>.conf(プレースホルダーは環境とコンポーネントです)を6つ作成してください(例:/root/ans/loops/matrix/dev-app.conf、/root/ans/loops/matrix/prod-worker.conf)。各ファイルには、env=<환경>とcomponent=<컴포넌트>(プレースホルダーは順に環境とコンポーネントです)の行が入ります。 /root/ans/loops/collected/へ、matrixの.conf6つをパターンで集めてコピーしてください。ファイル名を1つずつ書いてはいけません。/root/ans/loops/out/loops.jsonを作成してください。users(3件、各項目にprivilegedブール値)、matrix_files(6)を入れます。そして、2回目の実行結果を/root/ans/loops/out/run2.txtに保存してください。changed=0である必要があります。
参考
- ラボのPodはラボごとに新しく起動します。
/root/ans/inventory/hosts.iniがない場合は、最初のラボで作ったものと同じインベントリ(web1・web2・db1、ansible_host=127.0.0.1、ansible_port=2222、ansible_user=root、[prod:children]にweb・db)を先に作り直してください。構造は/opt/lab/fixtures/ansible/inventory.sample.iniを参考にできます。 loop: "{{ app_users }}"のように、変数をそのまま渡せます。- 組み合わせは、
"{{ envs | product(components) | list }}"の形式で作ります。 - よくある間違い1:
loopの中のタスクが冪等でないために、2回目の実行で繰り返しの回数分だけchangedが出ることです。 - よくある間違い2: パターンによる検索結果の順序に依存することです。順序は保証されません。
リストの繰り返しでディレクトリを3つ作る
/root/ans/loops/site.ymlでloopを使い、/root/ans/loops/simple/の下にalpha、beta、gammaディレクトリを作成してください。タスクは1つである必要があります。
loop:にリストを渡し、itemで参照します。タスクをコピーしないでください。
ディクショナリのリストを回す
/opt/lab/fixtures/ansible/users.ymlのapp_usersを読み込み、各項目のdirをmodeの権限で作成してください。/root/ans/loops/deploy(0750)、/root/ans/loops/metrics(0755)、/root/ans/loops/backup(0700)です。
フィクスチャのapp_usersをvars_filesで読み込みます。item.name、item.modeのように、フィールドでアクセスしてください。
条件に合う項目だけを処理する
同じ繰り返しにwhenを付けて、0755より厳しい項目のディレクトリにだけPRIVILEGEDファイルを残してください。/root/ans/loops/deploy/PRIVILEGEDと/root/ans/loops/backup/PRIVILEGEDは作られ、/root/ans/loops/metrics/PRIVILEGEDは作られてはいけません。
loopとwhenを一緒に使うと、条件が項目ごとに評価されます。modeが0755の項目は除外される必要があります。
ログに出力されるラベルを整理する
loop_controlのlabelでログを整理し、実行出力を/root/ans/loops/out/run.txtに保存してください。ログにitem=deployの形式の省略ラベルが見え、ディクショナリ全体が見えてはいけません。
loop_controlのlabelで省略します。ディクショナリ全体がログに出力されてはいけません。
条件が真になるまでリトライする
until/retries/delayを使った待機タスクを作成し、成功した結果を/root/ans/loops/out/ready.txtに、readyという内容で残してください。
until/retries/delayの3つが一緒に必要です。成功した結果をファイルに残してください。
2つのリストのすべての組み合わせを作る
環境(dev、stage、prod) × コンポーネント(app、worker)の組み合わせで、/root/ans/loops/matrix/<환경>-<컴포넌트>.conf(プレースホルダーは環境とコンポーネントです)を6つ作成してください(例: /root/ans/loops/matrix/dev-app.conf、/root/ans/loops/matrix/prod-worker.conf)。各ファイルには、env=<환경>とcomponent=<컴포넌트>(プレースホルダーは順に環境とコンポーネントです)の行が入ります。
productフィルターで組み合わせを作ります。環境3つ × コンポーネント2つ = 6つのファイルです。
パターンでファイルを集める
/root/ans/loops/collected/へ、matrixの.conf6つをパターンで集めてコピーしてください。ファイル名を1つずつ書いてはいけません。
ファイル名を1つずつ書かず、パターンで一覧を取得してください。内容が元のファイルと同じである必要があります。
繰り返し結果のレポートと再実行の確認
/root/ans/loops/out/loops.jsonを作成してください。users(3件、各項目にprivilegedブール値)、matrix_files(6)を入れます。そして、2回目の実行結果を/root/ans/loops/out/run2.txtに保存してください。changed=0である必要があります。
ユーザーごとのprivilegedかどうかと、組み合わせファイルの数をJSONにまとめ、2回目の実行がchanged=0かどうか確認してください。