てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] ロールを引数ありの関数のように使う

はじめに

Playbook を書いていて処理のかたまりをロール化したとき、一部の処理だけ変数で挙動を変えたいときはないでしょうか。この記事ではロールを引数ありの関数のように使う方法を紹介します。

Python でいうと以下のようなコードです。

  • greeting は、引数 msg を持つ
  • msg のデフォルト値は Hello, Role!
def greeting(msg="Hello, Role!"):
  print(msg)

greeting(msg="Good morning!")  # Good morning! を出力
greeting()                     # Hello, Role! を出力
  • 動作確認環境
    • Ansible 2.9.6

ファイル構成

こんなファイル構成です。

├── funcrole.yml   # ここからロールを呼ぶ
└── roles
    └── greeting
        ├── defaults
        │   └── main.yml  # デフォルトの引数値を定義
        └── tasks
            └── main.yml  # メイン処理

各ファイル内容

funcrole.yml

ロール呼び出し元 Playbook です。

---
- hosts: all
  gather_facts: false

  tasks:
    - name: import 
      import_role:
        name: greeting         # 関数的な指定
      vars:
        msg: Good morning!     # 引数的な指定

roles/greeting/tasks/main.yml

greeting ロールのメイン処理です。変数 msg の値を表示するだけです。

---
- name: greeting
  debug:
    msg: "{{ msg }}"

roles/greeting/defaults/main.yml

greeting ロールのデフォルト変数(デフォルト引数相当)の定義です。変数 msg が引数として綿割れなかった場合は、この値が使用されます。

---
msg: Hello Role!

実行1: 引数指定あり

先程の Playbook funcrole.yml を実行します。

Python のコード例でいう

greeting(msg="Good morning!") 

です。

$ ansible-playbook -i localhost, funcrole.yml 

PLAY [all] ******************************************************************************************************

TASK [greeting : graeting] **************************************************************************************
ok: [localhost] => {
    "msg": "Good morning!"
}

PLAY RECAP ******************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=

import_role タスクの vars で引数のように指定した msg: Good morning!msg の値 Good morning! が表示されましした。

実行2: 引数指定なし

funcrole.yml の内容を少し変えて、import_role タスクの vars の指定をなくして、引数なしの状態にして再度実行します。

Python のコード例でいう

greeting()

です。

---
- hosts: all
  gather_facts: false

  tasks:
    - name: import 
      import_role:        # vars なし
        name: greeting
$ ansible-playbook -i localhost, funcrole.yml 

PLAY [all] ********************************************************************************************************

TASK [greeting : greeting] ****************************************************************************************
ok: [localhost] => {
    "msg": "Hello Role!"
}

PLAY RECAP ********************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

引数(のようなもの)が与えられなかったので、roles/greeting/defaults/main.yml で定義した、msg の値 Hello Role!" が表示されました。

おわりに

ロールを引数ありの関数のように使う方法を紹介しました。ロールで処理をまとめつつ、一部だけ変えたいときに便利かと思います。

ただ、import_role タスクにあたえた vars はあくまでタスク変数のはずなのに、グローバル扱いになるようなのが不思議でした。 具体的には、後続のタスクでも 参照できてしまいました。

---
- hosts: all
  gather_facts: false

  tasks:
    - name: import 
      import_role:
        name: greeting
      vars:
        msg: Good morning!

    - name: debug
      debug:
        msg: "{{ msg }}"    # Good morning! が表示される