はじめに
タスクリスト全体を複製せずに、1 つの Playbook でホストごとに異なる作業を選択できます。ブール型のポリシー入力と OS ファクトを組み合わせ、構造化リストのすべての項目を処理して、登録した実際の調査結果を独立した承認判断に使用します。実際のファイルと明示的なクリーンアップで、選択された動作とスキップされた動作の両方を観察可能にします。
ブール型の入力とファクトでタスクを選択する
このステップでは、1 つの再利用可能な Playbook を 2 ホストで異なる動作にし、ポリシーが無効になったときに出力を明示的に削除します。
準備済み環境の web1 だけに、独立した承認入力 /home/automation/maintenance-approved があります。今はその入力を変更しないでください。最初のポリシー判断では、代わりにブール変数と検出した OS ファクトを使います。
コントローラーのプロジェクトに移動します。
cd /home/labex/project
ホスト変数ファイルは、データを各インベントリ名に関連付けます。文字列ではなく true/false 値のままにするため、YAML のブール値は引用符なしで記述してください。
cat > host_vars/web1.yml <<'YAML'
maintenance_enabled: true
YAML
cat > host_vars/web2.yml <<'YAML'
maintenance_enabled: false
YAML
when キーワードは、現在のホストについてブール式を評価します。式を Jinja の波括弧で囲まないでください。ここで and は、ポリシーの有効化と Debian 系のファクトの両方を要求します。not はブール値を反転し、or はどちらかの理由でクリーンアップ分岐を選択できるようにします。
cat > maintenance.yml <<'YAML'
- name: Apply a host-specific maintenance policy
hosts: all
gather_facts: true
tasks:
- name: Prepare the common policy directory
ansible.builtin.file:
path: /home/automation/maintenance-policy
state: directory
mode: "0750"
- name: Record enabled Debian maintenance
ansible.builtin.copy:
dest: /home/automation/maintenance-policy/enabled.txt
content: "Enabled maintenance\n"
mode: "0640"
when: maintenance_enabled and ansible_facts.os_family == "Debian"
- name: Remove the marker when the policy is disabled
ansible.builtin.file:
path: /home/automation/maintenance-policy/enabled.txt
state: absent
when: not maintenance_enabled or ansible_facts.os_family != "Debian"
YAML
共通ディレクトリは両ホストに存在します。ポリシーが有効な Debian ホストだけがマーカーを受け取り、相補的な absent タスクは、ポリシーが無効になったときに削除します。作成タスクをスキップするだけでは古いマーカーが残るため、クリーンアップを別の望ましい状態のタスクとして記述します。
ポリシーを検証し、適用します。
ansible-playbook maintenance.yml --syntax-check
ansible-playbook maintenance.yml
出力では、web1 と web2 に異なる changed/ok/skipped の判断が表示されるはずです。両ホストで実際のマーカーのメタデータを調べます。
ansible all -m ansible.builtin.stat -a 'path=/home/automation/maintenance-policy/enabled.txt'
Stat は web1 で exists true、web2 で false を報告するはずです。クリーンアップを試すため、両ホストのブール値を上書きします。JSON の追加変数は false のブール型を保ち、外側の単一引用符は JSON をシェルの解釈から保護します。
ansible-playbook maintenance.yml -e '{"maintenance_enabled":false}'
ansible all -m ansible.builtin.stat -a 'path=/home/automation/maintenance-policy/enabled.txt'
今度は両方のマーカーが存在しないはずです。一時的な上書きなしで実行し、保存されたホスト別のポリシーを復元します。
ansible-playbook maintenance.yml
web1 はマーカーを取り戻し、web2 は無効のままになるはずです。上書きは、保存済みのホスト変数ファイルを編集していません。
構造化ループのすべての項目を適用する
このステップでは、有効なホストで、宣言したすべての項目について実際の保守チェック記録を作成します。
YAML リストには、ダッシュで始まる複数の項目を含めます。以下の各項目は、name と purpose フィールドを持つマッピングです。all のグループ変数により、両ホストでこのリストを利用できますが、どのホストが出力を受け取るかは、引き続き既存のブール条件が決定します。
cat > group_vars/all.yml <<'YAML'
maintenance_checks:
- name: disk
purpose: Inspect disk space
- name: logs
purpose: Inspect application logs
- name: packages
purpose: Inspect package state
YAML
loop は、リストの各項目について 1 つのタスクを繰り返します。反復内では、item.name と item.purpose がその項目のフィールドを読みます。when 条件は、ホストと項目ごとに評価されます。以前のタスクとインデントをそろえ、既存の Playbook に次のタスクを追記してください。
cat >> maintenance.yml <<'YAML'
- name: Prepare checks only for enabled Debian hosts
ansible.builtin.file:
path: /home/automation/maintenance-policy/checks
state: directory
mode: "0750"
when: maintenance_enabled and ansible_facts.os_family == "Debian"
- name: Write every declared maintenance check
ansible.builtin.copy:
dest: "/home/automation/maintenance-policy/checks/{{ item.name }}.txt"
content: |
host={{ inventory_hostname }}
check={{ item.name }}
purpose={{ item.purpose }}
mode: "0640"
loop: "{{ maintenance_checks }}"
when: maintenance_enabled and ansible_facts.os_family == "Debian"
- name: Remove check outputs when the policy is disabled
ansible.builtin.file:
path: /home/automation/maintenance-policy/checks
state: absent
when: not maintenance_enabled or ansible_facts.os_family != "Debian"
YAML
クリーンアップタスクは、以前の有効なポリシーによる古い出力も含め、無効なホストのチェックディレクトリ全体を削除します。ループは、有効なホストに安定した内容と明示的な権限を書き込みます。
拡張した Playbook を適用します。
ansible-playbook maintenance.yml
web1 にはチェックごとに 1 つ、計 3 つのループ結果があるはずです。web2 はそれらの書き込みをスキップし、checks ディレクトリがないままになります。1 項目の成功をリスト全体の証拠とせず、web1 の実際の 3 成果物をすべて読んでください。
ansible web1 -m ansible.builtin.command -a 'cat /home/automation/maintenance-policy/checks/disk.txt /home/automation/maintenance-policy/checks/logs.txt /home/automation/maintenance-policy/checks/packages.txt'
出力は各記録で host=web1 を識別し、対応するチェック名と目的を示すはずです。無効なホストは別途調べます。
ansible web2 -m ansible.builtin.stat -a 'path=/home/automation/maintenance-policy/checks'
stat 結果は exists false を報告するはずです。これらの記録は保守チェックの指示を宣言するものであり、ディスク、ログ、パッケージの調査そのものを実行したと装うものではありません。
登録した調査結果に基づいて分岐する
このステップでは、実際の stat 結果を独立した判断入力として使用し、完全なポリシーが繰り返し時に安定することを確認します。
承認入力は maintenance_enabled とは別のものです。stat タスクが常に各ホストを調べ、register がそのホストの結果を保存します。stat.exists のブール値により、存在する入力と存在しないパスを安全に区別できます。調査と、相補的な出力のタスクを追記します。
cat >> maintenance.yml <<'YAML'
- name: Inspect the independent approval input
ansible.builtin.stat:
path: /home/automation/maintenance-approved
register: approval_info
- name: Record an existing approval input
ansible.builtin.copy:
dest: /home/automation/maintenance-policy/approved.txt
content: "Approval input exists\n"
mode: "0640"
when: approval_info.stat.exists
- name: Remove the output when approval input is absent
ansible.builtin.file:
path: /home/automation/maintenance-policy/approved.txt
state: absent
when: not approval_info.stat.exists
YAML
copy タスクは登録した exists 値を利用します。absent タスクは逆の場合を扱うため、承認入力を削除すると、古い承認出力も削除されます。この分岐は、固定の debug メッセージではなく、調査した状態に基づきます。
完全なポリシーを実行します。
ansible-playbook maintenance.yml
準備済みの承認入力は web1 だけにあるので、approved.txt も web1 だけに存在するはずです。両方の実際の出力パスを調べます。
ansible all -m ansible.builtin.stat -a 'path=/home/automation/maintenance-policy/approved.txt'
web1 は exists true、web2 は false を報告するはずです。Playbook を繰り返します。
ansible-playbook maintenance.yml
recap の両行が changed=0、failed=0、unreachable=0 を報告するはずです。条件が false のところではタスクのスキップが想定されますが、必要なすべてのループ項目と、選択された出力は、引き続き正しい内容で存在する必要があります。
まとめ
ホスト別のブールデータと検出したファクトでタスクを選択し、ループ内の各マッピングを処理して、登録した stat メタデータで分岐しました。作成のスキップが古い状態を取り消すと思い込まず、相補的な absent タスクで古い出力を削除しました。両ホストは、不要な繰り返し変更なしに、それぞれ異なるポリシーの結果へ収束しました。


