てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] ansible.utils.fact_diff フィルターで変数間のdiffをする(モジュールではなく)

この記事は Ansible Advent Calendar 2023 1日目の記事です。

はじめに

先日リリースされた ansible.utils コレクションのバージョン 3.0.0 と 2.12.0 で、ansible.utils.fact_diff フィルタープラグインが追加されました。

(3.0.0 からは ansible-core 2.14.0 以上が要件)

これまでも ansible.utils.fact_diff モジュールがあって、変数同士の diff を見るのに便利でした。これのフィルター版です。

モジュールは一つのタスクとして独立して定義しておく必要があります。一方、フィルターの場合は、他のモジュールのオプションや vars ディレクティブによる変数定義に組み込んだりできます。

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

  • ansible-core 2.15.6
  • ansible.utils 3.0.0

例1: ごく簡単な例

使い方の基本を抑えるために、とても簡単な例を試します。

ansible.builtin.debug モジュールの msg オプションに、2つのリストの比較結果を指定しています。

    - name: Debug fact_diff filter
      ansible.builtin.debug:
        msg: "{{ before | ansible.utils.fact_diff(after) }}"
      vars:
        before:
          - 1
          - 2
          - 3
        after:
          - 1
          - 22
          - 3

実行結果は以下の通り。Unified Diff 形式の結果が1行1要素のリストとして表示されました。ansible.utils.fact_diff モジュールでいう、戻り値の中の diff_lines に相当する形式のようです。

TASK [Debug fact_diff filter] ******************************************************************************
ok: [ios01] => {
    "msg": [
        "--- before",
        "+++ after",
        "@@ -1,3 +1,3 @@",
        " 1",
        "-2",
        "+22",
        " 3",
        ""
    ]
}

なお、似たようなことを ansible.utils.fact_diff モジュールでやる場合は以下のような書き方です。

    # モジュールの場合
    - name: Debug fact_diff module
      ansible.utils.fact_diff:
        before:
          - 1
          - 2
          - 3
        after:
          - 1
          - 22
          - 3

以下のような結果になります。register で比較結果を変数にいれることもできますが、何もしなくてもログに表示されます。

# モジュールの場合
TASK [Debug fact_diff module] ***********************************************************************
--- before
+++ after
@@ -1,3 +1,3 @@
 1
-2
+22
 3

changed: [ios01]

例2: 少し工夫した例(比較対象外の指定)

比較はしたいけどここは無視したいというケースもあります。ansible.utils.fact_diff モジュールでは、plugins > vars > skip_lines オプションで指定するものです。フィルターにも同じ機能があります。

以下の例では、Cisco IOS の機器のインターフェースの description を変更する際、前後のコンフィグ間の diff を表示する例です。何も意識しないと、設定の内容に直接関係ない行が差分として検出されてしまうので、無視する行を指定しています。

    # 事前コンフィグの取得
    - name: Get before config
      cisco.ios.ios_command:
        commands:
          - show running-config
      register: before_running_config
  
    # 設定変更
    - name: Configure
      cisco.ios.ios_interfaces:
        config:
          - name: GigabitEhternet0/1
            description: hogehoge!!

    # 事後コンフィグの取得        
    - name: Get after config
      cisco.ios.ios_command:
        commands:
          - show running-config
      register: after_running_config

    # コンフィグ差分の表示
    - name: Debug diff
      ansible.builtin.debug:
        msg: "{{ before | ansible.utils.fact_diff(after, plugin=plugin) }}"   # plugin オプションの指定
      vars:
        before: "{{ before_running_config.stdout[0] }}"
        after: "{{ after_running_config.stdout[0] }}"
        plugin:    # plugin オプションに指定する値の定義
          vars:
            skip_lines:    # 無視したい行の定義
              - "^! Last configuration change at.+"
              - "^Current configuration .+ "

ansible.utils.fact_diff(after, plugin=plugin) のところがやや分かりにくいかもしれませんが、plugin オプションに、変数 plugin を指定しています(ここではタスクの vars で定義)。

結果は以下のとおりです。

TASK [Get before config] ***********************************************
ok: [ios01]

TASK [Configure] *******************************************************
changed: [ios01]

TASK [Get after config] ************************************************
ok: [ios01]

TASK [Debug diff] ******************************************************
    "msg": [
        "--- before",
        "+++ after",
        "@@ -75,7 +75,7 @@",
        "  media-type rj45",
        " !",
        " interface GigabitEthernet0/1",
        "- description hogehoge",
        "+ description hogehoge!!",
        "  ip address 172.16.2.1 255.255.255.252",
        "  no ip redirects",
        "  duplex auto",
        ""
    ]
}

おわりに

ansible.utils.fact_diff モジュールと同等の機能を、ansible.utils.fact_diff フィルターでもできそうだという感覚が得られました。

フィルターのほうが小回りがきくので、今後使うことが増えるかもしれません。