てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] ロールの実行に必要な変数のチェック「だけ」する(ロールの処理自体はしない)

はじめに

以前の記事でもご紹介しましたが、ロールの実行に必要な変数をチェックする「Role argument validation」という機能があります。

tekunabe.hatenablog.jp

ロールの meta/argument_specs.yml というファイルに、どういう変数が必須か、型は何かなどを定義すると、Playbook からロールを呼ぶ際に、冒頭で変数のチェックをしてくれます。要件を満たさない場合はロールが実行されません。

ロールの実行と変数のチェックがセットであるため、ただ変数のチェックのみしたい(テスト目的など)場合は少々不都合です。

そこで利用できるのが、ansible.builtin.validate_argument_spec モジュールです。

この記事では簡単な検証をした結果をまとめます。

  • 検証環境
    • ansible-core 2.16.0

サンプル

roles ディレクトリ配下に myapp ロールを作成し、その中の meta/argument_specs.yml に以下のファイルを用意します。

myapp_intint で必須、myapp_strstr で任意、という定義です。

---
argument_specs:
  main:          # main.yml に対応
    short_description: The main entry point for the myapp role
    options:    #ここから変数の仕様定義
      myapp_int:
        type: "int"
        required: true
        description: "The integer value"

      myapp_str:
        type: "str"
        description: "The string value"

上記のファイルを利用し、変数のチェックをする Playbook は以下の通りです。

---
- name: Test Play
  hosts: localhost
  connection: local
  gather_facts: false

  tasks:
    - name: Verify variables by argument_specs.yml
      ansible.builtin.validate_argument_spec:
        argument_spec: "{{ (lookup('ansible.builtin.file', spec_file) | from_yaml)['argument_specs']['main']['options'] }}"
        provided_arguments: "{{ my_parameters }}"   # チェックさせたい変数
      vars:
        spec_file: roles/myapp/meta/argument_specs.yml
        my_parameters:    # チェックさせたい変数を束ねてる
          myapp_int: 12345   # チェックさせたい変数
          myapp_str: sakana  # チェックさせたい変数

argument_spec オプションに、argument_specs.yml の中身を渡しています。

provided_arguments オプションにはチェックさせたい変数を指定します。ここでは、vars ディレクティブ配下の my_parameters の中身(myapp_intmyapp_str)がチェックさせたい変数です。provided_arguments オプションの指定なので、チェックしたい変数が別の場所(インベントリ変数、Play 変数、extra vars など)してあるなら指定不要です。

正常時の結果

先程の my_parameters は要件を満たしています。この状態で Playbook を実行します。

PLAY [Test Play] *****************************************************************************************************

TASK [Verify variables by argument_specs.yml] *************************************************************************
ok: [localhost]

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

ok になりました。

チェックだけなので、ロール自体の処理は実行されません。

異常時の結果

今度は要件を満たさないようにしてみます。

        # 略
        my_parameters:    # チェックさせたい変数を束ねてる
          myapp_int: damedesuyo   # int にすべきところを意図的に文字列
          myapp_str: sakana

Playbook 実行結果は以下のとおりです。myapp_intint にできないという親切なメッセージが表示されました。

fatal: [localhost]: FAILED! => {
    "argument_errors": [
        "argument 'myapp_int' is of type <class 'str'> and we were unable to convert to int: <class 'str'> cannot be converted to an int"
    ],
    "argument_spec_data": {
        "myapp_int": {
            "description": "The integer value",
            "required": true,
            "type": "int"
        },
        "myapp_str": {
            "description": "The string value",
            "required": true,
            "type": "str"
        }
    },
    "changed": false,
    "msg": "Validation of arguments failed:\nargument 'myapp_int' is of type <class 'str'> and we were unable to convert to int: <class 'str'> cannot be converted to an int",
    "validate_args_context": {}
}

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

まとめ

用途は限られるかもしれませんが、ロールの処理はしたくないけど変数のチェックだけしたい、というときには有効な手段だと思います。

参考

docs.ansible.com

おまけ

ロールの実行に必要な変数のチェックという用途とは異なりますが、何かしらの変数のチェックを JSON Schema で行いたい場合は、ansible.utils コレクション内の validate モジュールなどが利用できます。