てくなべ (tekunabe)

ansible / network / automation / StackStorm

[Ansible] read_csv モジュールの基本的な使い方(CSVファイルをリストやディクショナリとして読み込む)

■ はじめに

2019年5月リリース予定の Ansible 2.8 では、CSV ファイルをリストやディクショナリとして読み込む read_csv モジュール が導入されます。カンマ区切りのファイルだけでなく、別のデリミタ(;など)を指定することもできます。

この記事では、 read_csv モジュールの公式ドキュメントに記載されている使用例をベースにして、使い方を説明します。

なお、公式ドキュメントの使用例は、Playbook 単位ではなくtask 単位で記載されています。この記事では Playbook 単位で例示します。

似たものとして、csvfile lookup プラグインがあります。csvfile lookup プラグインが「ローカルのCSVファイル」の「指定条件の値を取得」するのに対して、read_csv モジュールは、「リモート(またはローカル)のCSVファイル」の「全体をリストまたはディクショナリとして取得」します。

動作確認環境

目次


■ 単純にCSVファイルを読み込んでリストにする

CSV ファイル

以下のヘッダー付き CSV ファイルを利用します。

name,uid,gid
dag,500,500
jeroen,501,500

Playbook

単純にCSVファイルを読み込んでリストにするシンプルな Playbook です。

- hosts: testsv
  gather_facts: no

  tasks:
    - name: Read users from CSV file and return a list
      read_csv:
        path: users.csv
      register: users
      delegate_to: localhost  # ここを省略するとリモートのファイルを参照

    - name: debug csv
      debug:
        msg: "{{ users }}"
  • read_csv タスク
    • path オプション
      • 読み込む CSV ファイルのパスを指定します。(必須)
    • delegate_to ディレクティブ
      • delegate_to: localhost という指定で、リモートではなくローカル(ansible-playbook コマンド自体を実行しているマシン)上の path を参照します。省略すると、リモートの path を参照します。
  • debug タスク
    • msg オプション
      • リストとして取得した CSV ファイルの内容を単純に全部出力します。

実行ログ

Playbook を実行します。

$  ansible-playbook -i ../inventory csv_simple.yml 

PLAY [testsv] *******************************************************************************************

TASK [Read users from CSV file and return a list] *******************************************************
ok: [testsv]

TASK [debug csv] ****************************************************************************************
ok: [testsv] => {
    "msg": {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        }, 
        "changed": false, 
        "dict": {}, 
        "failed": false, 
        "list": [
            {
                "gid": "500", 
                "name": "dag", 
                "uid": "500"
            }, 
            {
                "gid": "500", 
                "name": "jeroen", 
                "uid": "501"
            }
        ]
    }
}

PLAY RECAP **********************************************************************************************
testsv                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

debug タスクの出力により、CSV ファイルの内容がリストとして、users.list に格納されていることが分かります。各リスト内の要素は CSV ファイルの1行目のヘッダー gid,name,uid が、キーとなるディクショナリの構造になります。

特定の値を取得する場合、例えば、1番目(0オリジン)の name であれば、"{{ users.list.1.name }}" と指定すすると、jeroen という値を取得できます。

他、SQL の where 句のような条件で抽出するには selectattrを使用します。例えば、gid500 以上の name のリストであれば、

"{{ `users.list | selectattr('gid', '==', '500') | map(attribute='name') | list }}"

と指定すると ["dag", "jeroen"]という値を取得できます。


CSV ファイルを読み込んでディクショナリにする

CSV ファイル

先ほどと同じく、以下のヘッダー付き CSV ファイルを利用します。

name,uid,gid
dag,500,500
jeroen,501,500

Playbook

CSV ファイルを読み込んでディクショナリにする Playbook です。

- hosts: testsv
  gather_facts: no

  tasks:
    - name: Read users from CSV file and return a list
      read_csv:
        path: users.csv
        key: name
      register: users
      delegate_to: localhost  # ここを省略するとリモートのファイルを参照

    - name: debug csv
      debug:
        msg: "{{ users }}"
  • read_csv タスク
    • key オプション
      • ディクショナリとして取得する際のキーを指定します。
  • debug タスク
    • msg オプション
      • ディクショナリとして取得した CSV ファイルの内容を単純に全部出力します。

実行ログ

Playbook を実行します。

$  ansible-playbook -i ../inventory csv_dict.yml 

PLAY [testsv] *******************************************************************************************

TASK [Read users from CSV file and return a list] *******************************************************
ok: [testsv]

TASK [debug csv] ****************************************************************************************
ok: [testsv] => {
    "msg": {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        }, 
        "changed": false, 
        "dict": {
            "dag": {
                "gid": "500", 
                "name": "dag", 
                "uid": "500"
            }, 
            "jeroen": {
                "gid": "500", 
                "name": "jeroen", 
                "uid": "501"
            }
        }, 
        "failed": false, 
        "list": []
    }
}

PLAY RECAP **********************************************************************************************
testsv                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

debug タスクの出力により、CSV ファイルの内容がディクショナリとして、users.dict に格納されていることが分かります。key オプションで指定した name にあたる値がキーとなる構造になります。

特定の値を取得する場合、例えば namedaguid の場合、"{{ users.dict.dag.uid }}" と指定すると、500 という値を取得できます。


■ ヘッダーのないセミコロン区切りのファイルを読み込んでリストにする

カンマでなく、別のデリミタの場合です。

ファイル

以下のヘッダーのないセミコロン区切りのファイルを利用します。

dag;500;500
jeroen;501;500

Playbook

ヘッダーのないセミコロン区切りのファイルを読み込んでリストにする Playbook です。

- hosts: testsv
  gather_facts: no

  tasks:
    - name: Read users from CSV file and return a list
      read_csv:
        path: users_wo_headers.csv
        fieldnames: name,uid,gid
        delimiter: ';'
      register: users
      delegate_to: localhost  # ここを省略するとリモートのファイルを参照

    - name: debug csv
      debug:
        msg: "{{ users }}"
  • read_csv タスク
    • fieldnames オプション
      • ヘッダーのないファイルの場合にそれぞれのカラムにつけヘッダー名です。
    • delimiter オプション
      • 区切り文字となるデリミタを指定します。今回の読み込みファイルは ; 区切りなので、delimiter: ';' を指定します。
  • debug タスク
    • msg オプション
      • リストとして取得したファイルの内容を単純に全部出力します。

実行ログ

Playbook を実行します。

$  ansible-playbook -i ../inventory csv_3.yml 

PLAY [testsv] *******************************************************************************************

TASK [Read users from CSV file and return a list] *******************************************************
ok: [testsv]

TASK [debug csv] ****************************************************************************************
ok: [testsv] => {
    "msg": {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        }, 
        "changed": false, 
        "dict": {}, 
        "failed": false, 
        "list": [
            {
                "gid": "500", 
                "name": "dag", 
                "uid": "500"
            }, 
            {
                "gid": "500", 
                "name": "jeroen", 
                "uid": "501"
            }
        ]
    }
}

PLAY RECAP **********************************************************************************************
testsv                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


debug タスクの出力により、ヘッダーのない ; 区切りのファイルの内容がリストとして、users.list に格納されていることが分かります。各リスト内の要素は fieldnames オプションで指定した、gid,name,uid が、キーとなるディクショナリの構造になります。


■ まとめ

公式ドキュメントの使用例をベースにしてread_csv モジュール の使い方を説明しました。

他に「こんなことできるかな?」と気になる事がありましたら、公式ドキュメントで詳細をご確認ください。

docs.ansible.com

また、read_csv モジュールは Files modules に分類されています。Files modules には、他にも、指定した正規表現にマッチするすべての文字列を置換する replace や、行ではなくブロック単位で編集する blockinfile などのモジュールがあります。詳細は Files modules の一覧からご確認ください。