うさラボ

お勉強と備忘録

ansible.utilsコレクションのフィルタ(keep_keys/remove_keys/replace_keys)を試す

この記事はアドベントカレンダー20日目の記事です

qiita.com

はじめに

最近showコマンドの結果をパースして、パースした結果をこねくり回すことが増えてきました。 そんな中で、特定のKeyのみを残す、特定のKeyを削除する必要があり自作フィルタを使っていました 。

ansible.utils 2.5.0(2022-01-31リリース)から追加されたxxx_keys系のフィルタが自分が作っていたものとほぼ同じ動きをするフィルタだったので動作確認をして置き換えましたので紹介します。

昨年の記事で試したrouteのDiffをとる前に、データ操作としてJinja2テンプレートをいじったり、カスタムフィルタを使ったりしましたが、別解のようなイメージです。

usage-automate.hatenablog.com

keep_keysフィルタ

文字通り、指定されたKeyのみを保持するフィルタです

サンプルプレイブック

---
- hosts: localhost
  gather_facts: false

  vars:
    routes:
      - network: "195.0.0.0"
        distance: "110"
        mask: "24"
        metric: "11"
        nexthop_if: "FastEthernet0/0.100"
        nexthop_ip: "194.0.0.2"
        protocol: "O"
        type: "IA"
        uptime: "00:05:45"
      - network: "0.0.0.0"
        distance: "110"
        mask: "0"
        metric: "1"
        nexthop_if: "FastEthernet0/0.100"
        nexthop_ip: "194.0.0.2"
        protocol: "O"
        type: "E2"
        uptime: "00:05:35"

  tasks:
    - name: keep_keys
      ansible.builtin.debug:
        msg: "{{ routes | ansible.utils.keep_keys(target=['network','distance']) }}"

フィルタの変数targetにリストで渡した文字列のKeyのみを保持します

targerはregrexやstarts_with/ends_withなど正規表現を使ってマッチさせることも可能です

keep_keys(target=['^ne','distance'], matching_parameter= 'starts_with')

実行結果

TASK [keep_keys] ************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "distance": "110",
            "network": "195.0.0.0"
        },
        {
            "distance": "110",
            "network": "0.0.0.0"
        }
    ]
}

targetsに指定したnetwork/distanceのみのデータに整形できました

remove_keysフィルタ

こちら指定したキーを削除するフィルタになります

uptimeを取り除く例

---
- hosts: localhost
  gather_facts: false

  vars:
    routes:
      - network: "195.0.0.0"
        distance: "110"
        mask: "24"
        metric: "11"
        nexthop_if: "FastEthernet0/0.100"
        nexthop_ip: "194.0.0.2"
        protocol: "O"
        type: "IA"
        uptime: "00:05:45"
      - network: "0.0.0.0"
        distance: "110"
        mask: "0"
        metric: "1"
        nexthop_if: "FastEthernet0/0.100"
        nexthop_ip: "194.0.0.2"
        protocol: "O"
        type: "E2"
        uptime: "00:05:35"

  tasks:
    - name: remove_keys
      ansible.builtin.debug:
        msg: "{{ routes | ansible.utils.remove_keys(target=['uptime']) }}"

keep_keysフィルタと同様に変数targetにリストで渡します
matching_parameterも同様に利用可能です

出力

TASK [remove_keys] *************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "distance": "110",
            "mask": "24",
            "metric": "11",
            "network": "195.0.0.0",
            "nexthop_if": "FastEthernet0/0.100",
            "nexthop_ip": "194.0.0.2",
            "protocol": "O",
            "type": "IA"
        },
        {
            "distance": "110",
            "mask": "0",
            "metric": "1",
            "network": "0.0.0.0",
            "nexthop_if": "FastEthernet0/0.100",
            "nexthop_ip": "194.0.0.2",
            "protocol": "O",
            "type": "E2"
        }
    ]
}

フィルタにかけた後のデータからuptimeが消えたことが確認できます

replace_keysフィルタ

replace_keysフィルタはKeyの名前を変えることができるフィルタです

---
- hosts: localhost
  gather_facts: false

  vars:
    routes:
      - network: "195.0.0.0"
        distance: "110"
        mask: "24"
        metric: "11"
        nexthop_if: "FastEthernet0/0.100"
        nexthop_ip: "194.0.0.2"
        protocol: "O"
        type: "IA"
        uptime: "00:05:45"
      - network: "0.0.0.0"
        distance: "110"
        mask: "0"
        metric: "1"
        nexthop_if: "FastEthernet0/0.100"
        nexthop_ip: "194.0.0.2"
        protocol: "O"
        type: "E2"
        uptime: "00:05:35"

  tasks:
    - name: replace_keys
      ansible.builtin.debug:
        msg: "{{ routes | ansible.utils.replace_keys(target=[{'before':'nexthop_if', 'after':'nexthop_interface'}]) }}"

フィルタの変数targetsには[{before: XXX, after: XXXZ}]とどのKeyを何に変えるかを定義する必要があります
matching_parameterはkeep_keys/remove_keysと同様に利用可能です

nexthop_ifのKeyをnexthop_interfaceに変更します。

出力

TASK [replace_keys] *********************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "distance": "110",
            "mask": "24",
            "metric": "11",
            "network": "195.0.0.0",
            "nexthop_interface": "FastEthernet0/0.100",
            "nexthop_ip": "194.0.0.2",
            "protocol": "O",
            "type": "IA",
            "uptime": "00:05:45"
        },
        {
            "distance": "110",
            "mask": "0",
            "metric": "1",
            "network": "0.0.0.0",
            "nexthop_interface": "FastEthernet0/0.100",
            "nexthop_ip": "194.0.0.2",
            "protocol": "O",
            "type": "E2",
            "uptime": "00:05:35"
        }
    ]
}

nexthop_ifをnexthop_interfaceに変更できました。

まとめ

ansible.utilsの3つのフィルタを紹介しました
コレクションで提供されている便利なフィルタは積極的に使っていきたいですね。

ちなみに

書いてる時に思い出しましたがすべて、json_queryでもできますね笑

---
- hosts: localhost
  gather_facts: false

  vars:
    routes:
      - network: "195.0.0.0"
        distance: "110"
        mask: "24"
        metric: "11"
        nexthop_if: "FastEthernet0/0.100"
        nexthop_ip: "194.0.0.2"
        protocol: "O"
        type: "IA"
        uptime: "00:05:45"
      - network: "0.0.0.0"
        distance: "110"
        mask: "0"
        metric: "1"
        nexthop_if: "FastEthernet0/0.100"
        nexthop_ip: "194.0.0.2"
        protocol: "O"
        type: "E2"
        uptime: "00:05:35"

  tasks:
    - name: json_query(keep_keys)
      ansible.builtin.debug:
        msg: "{{ routes | community.general.json_query(query_string) }}"
      vars:
        query_string: "[*].{network: network, distance: distance}"

    - name: json_query(remove_keys)
      ansible.builtin.debug:
        msg: "{{ routes | community.general.json_query(query_string) }}"
      vars:
        query_string: "[*].{network: network,
                            distance: distance,
                            mask: mask,
                            metric: metric,
                            nexthop_if: nexthop_if,
                            nexthop_ip: nexthop_ip,
                            protocol: protocol,
                            type: type}"

    - name: json_query(replace_keys)
      ansible.builtin.debug:
        msg: "{{ routes | community.general.json_query(query_string) }}"
      vars:
        query_string: "[*].{network: network,
                            distance: distance,
                            mask: mask,
                            metric: metric,
                            nexthop_interface: nexthop_if,
                            nexthop_ip: nexthop_ip,
                            protocol: protocol, 
                            type: type}"

実行結果

TASK [json_query(keep_keys)] ***************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "distance": "110",
            "network": "195.0.0.0"
        },
        {
            "distance": "110",
            "network": "0.0.0.0"
        }
    ]
}

TASK [json_query(remove_keys)] **************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "distance": "110",
            "mask": "24",
            "metric": "11",
            "network": "195.0.0.0",
            "nexthop_if": "FastEthernet0/0.100",
            "nexthop_ip": "194.0.0.2",
            "protocol": "O",
            "type": "IA"
        },
        {
            "distance": "110",
            "mask": "0",
            "metric": "1",
            "network": "0.0.0.0",
            "nexthop_if": "FastEthernet0/0.100",
            "nexthop_ip": "194.0.0.2",
            "protocol": "O",
            "type": "E2"
        }
    ]
}

TASK [json_query(replace_keys)] ***************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "distance": "110",
            "mask": "24",
            "metric": "11",
            "network": "195.0.0.0",
            "nexthop_interface": "FastEthernet0/0.100",
            "nexthop_ip": "194.0.0.2",
            "protocol": "O",
            "type": "IA"
        },
        {
            "distance": "110",
            "mask": "0",
            "metric": "1",
            "network": "0.0.0.0",
            "nexthop_interface": "FastEthernet0/0.100",
            "nexthop_ip": "194.0.0.2",
            "protocol": "O",
            "type": "E2"
        }
    ]
}