【Ansible】csvファイルから変数を設定する(read_csvモジュール)

## はじめに
これまで、Ansibleで変数を設定するときは、group_varsやroles内のvarsあたりに書いてましたが、read_csvモジュールを使うことでcsvファイルから変数の値の読み取りができることを知り、実際に使ってみたので備忘録として記事にしました。

## 前提
・Ansibleのplaybookが実行できる。
・Ansibleのディレクトリ構成が分かる。
・csvファイルを知っている。

## 実行環境
|環境|バージョン|
|--|--|
|Ansible|2.14.1|
|python|3.10.6|

## ディレクトリ構成
```
├─ playbook.yaml  
└─ roles/
    └─ csv_test/
        ├─ files/
　      │   └─ csvfile.csv  //読み込むcsvファイル
　      └─ tasks/
　          └─ main.yaml
```
## csvfile.csv の中身
適当なcsvファイルを用意しました。
```
id,name,area
1,tokyo,kanto
2,osaka,kinki
3,chiba,kanto
4,kyoto,kinki
5,aichi,chubu
```
## コード(csvファイルの内容をcsv_dataの変数に格納・表示)
**playbook.yaml**
```
- hosts: localhost
  become: yes

  roles:
   - csv_test
```

**roles/csv_test/tasks/main.yaml**
```
- name: csvfile.csvを取得
  read_csv: 
    path: roles/csv_test/files/csvfile.csv   //csvファイルのパス
  register: csv_data                        //取得したデータをcsv_dataという変数に格納
  delegate_to: localhost                   //csvファイルをローカルから参照する

- name: csv_dataを表示
  debug:
    var: csv_data　                    //csv_dataの値を表示する
```

このplaybookは、roles内のfilesにcsvファイルを配置し、main.yamlのread_csvモジュールで読み取り、出力するための最小の構成です。
 
**path**にはplaybook.yamlからcsvファイルまでの相対パスを記載しています。

**delegate_to: localhost**を指定することで、Ansibleはローカル(Ansibleを実行する側)のファイルを参照します。この行を省略すると、リモート側(Ansibleを実行する対象)のファイルを参照します。今回はrolesのfilesの中にファイルを格納しているため、記載する必要があります。

**debug**でcsv_dataの変数に格納した値を表示しています。

## 実行結果

```
PLAY[localhost]****************************************************************************************

TASK [csv_test : csvfile.csvを取得]********************************************************************
ok: [localhost]

TASK [csv_test : csv_dataを表示]***********************************************************************
ok: [localhost] => {
    "csv_data": {
        "changed": false,
        "dict": {},
        "failed": false,
        "list": [
            {
                "area": "kanto",
                "id": "1",
                "name": "tokyo"
            },
            {
                "area": "kinki",
                "id": "2",
                "name": "osaka"
            },
            {
                "area": "kanto",
                "id": "3",
                "name": "chiba"
            },
            {
                "area": "kinki",
                "id": "4",
                "name": "kyoto"
            },
            {
                "area": "chubu",
                "id": "5",
                "name": "aichi"
            }
        ]
    }
}

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

このように、csvファイルの一行目に記載した項目がキーとなる辞書型のリストが出力され、
**csv_data**の**list**の中にcsvファイルの内容がリストで格納されていることが分かります。

以下は、格納した変数を実際に使用するためのコード例です。

## コード(csv_dataから指定した列を取得)
**roles/csv_test/tasks/main.yaml**
```
- name: csvfile.csvを取得
  read_csv: 
    path: roles/csv_test/files/csvfile.csv   //csvファイルのパス
  register: csv_data                        //取得したデータをcsv_dataという変数に格納
  delegate_to: localhost                   //csvファイルをローカルから参照する

- name: csv_dataを表示
  debug:
    var: csv_data　                    //csv_dataの値を表示する
  
- name: use_list
  debug:
    msg: "{{ item.area }}"          //csv.dataの中のareaの列を1行ずつメッセージ出力
  loop: "{{ csv_data.list }}"      //csv_data.listでループさせる
```
**csv_data**の**list**の中にcsvファイルの内容がリストで格納されているため、loopにはcsv_data.listを指定します。

## 実行結果
```
PLAY[localhost]******************************************************************************************

TASK [csv_test : csvfile.csvを取得]**********************************************************************
ok: [localhost]

TASK [csv_test : csv_dataを表示]*************************************************************************
ok: [localhost] => {
    "csv_data": {
        "changed": false,
        "dict": {},
        "failed": false,
        "list": [
            {
                "area": "kanto",
                "id": "1",
                "name": "tokyo"
            },
            {
                "area": "kinki",
                "id": "2",
                "name": "osaka"
            },
            {
                "area": "kanto",
                "id": "3",
                "name": "chiba"
            },
            {
                "area": "kinki",
                "id": "4",
                "name": "kyoto"
            },
            {
                "area": "chubu",
                "id": "5",
                "name": "aichi"
            }
        ]
    }
}

TASK [csv_test : use_list] ****************************************************************************
ok: [localhost] => (item={'id': '1', 'name': 'tokyo', 'area': 'kanto'}) => {
    "msg": "kanto"
}
ok: [localhost] => (item={'id': '2', 'name': 'osaka', 'area': 'kinki'}) => {
    "msg": "kinki"
}
ok: [localhost] => (item={'id': '3', 'name': 'chiba', 'area': 'kanto'}) => {
    "msg": "kanto"
}
ok: [localhost] => (item={'id': '4', 'name': 'kyoto', 'area': 'kinki'}) => {
    "msg": "kinki"
}
ok: [localhost] => (item={'id': '5', 'name': 'aichi', 'area': 'chubu'}) => {
    "msg": "chubu"
}

PLAY RECAP ********************************************************************************************
localhost      : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```
実行結果を見ると、csvファイルのname列を1行ずつ表示できたことが分かります。
ここまで来れば後は通常の変数の使い方と同じように使用することができます。

# さいごに
最後まで読んでいただきありがとうございました！
今後もAnsible関連の記事を書きたいと思うのでよろしくお願いします！

## 参考
https://docs.ansible.com/ansible/latest/collections/community/general/read_csv_module.html