AnsibleでREST APIリクエストする例

# AnsibleでREST APIリクエストする方法
Ansibleを使う時、当然Playbookを記述するわけですが、以下の観点からなるべく[shell](https://docs.ansible.com/ansible/2.9/modules/shell_module.html#shell-module)モジュールや[command](https://docs.ansible.com/ansible/2.9/modules/command_module.html#command-module)モジュールなどのコマンドを記述するモジュールを使わず、その対象機器に特化したモジュールを使えないか検討する必要があります。

- Playbookとしての冪等性を担保するため
- 宣言型の記述により、このPlaybookを流したらどういう状態になるか読んでもわかるようにするため

ただ、どうしても最適なモジュールがない場合は、Command系のモジュールの使用を検討することになりますが、対象機器がREST APIのインターフェースを持っている場合は、AnsibleからAPIをリクエストして機器を操作する方法も考えられます。

## REST APIリクエストをするモジュール
[uri](https://docs.ansible.com/ansible/2.9/modules/uri_module.html#uri-module)というモジュールを利用する。  
例えばGETする場合はこんなTask記述になる。

```yaml
  tasks:
    - name: Get event list
      uri:
        url: "https://xxxxx/xxxxxx/xxxx" 
        headers:
          Accept: "xxxxxxx"
          Authorization: "xxxxxxxx"
        status_code: 200
        method: GET
        return_content: yes
      register: result_get
```
指定したURLに対してGETリクエストして、結果を`result_get`へ保存する。REST APIは、Webサービスによって認証の仕組み（Tokenの送信）がほとんどの場合必要なので、ヘッダとして付与する。

## REST APIリクエストする例
ここでは、超私的なニーズの元、手頃なサービスとして[TimeTree](https://timetreeapp.com/)のAPIを例として取り上げる。

- [TimeTree APIの概要](https://developers.timetreeapp.com/ja/docs/api/overview)

### 実行環境
- Ansible 2.9.4

### 手順
1. App Consoleへのアクセスする  
TimeTreeの開発者向け[App Console](https://timetreeapp.com/developers/calendar_apps)アクセスする
2. Personal Accesss Tokenを作成する
![accessToken.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566760/be8f5226-20ad-ebb1-85b3-c9beb9805996.png)


3. 発行されたTokenを保存しておく。
4. 自分のカレンダーIDを保存しておく。  
自分のカレンダーへアクセスした時のURLの最後の要素がカレンダーID。
`https://timetreeapp.com/calendars/<カレンダーID>`
ここまでで、TimeTreeへAPIでアクセスするために必要な情報として以下が揃った。
    - アクセストークン
    - カレンダーID  


5. AnsibleでAPIリクエスト  
このPlaybookは、指定したカレンダーに対して以下を行う。
    - 直近のデータを取得（デバッグ的に）
    - CSVからカレンダー登録するデータを読み込み
    - APIを使って一括登録

```yaml:createEvents.yml
- name: create events
  hosts: localhost
  gather_facts: no
  connection: local
  vars:
    access_token: <Access Token>
    calender_id: <CalenderID>

  tasks:
    - name: Get event list
      uri:
        url: "https://timetreeapis.com/calendars/{{ calender_id }}/upcoming_events?timezone=Asia/Tokyo&days=3&include=creator,label,attendees" 
        headers:
          Accept: "application/vnd.timetree.v1+json"
          Authorization: "Bearer {{ access_token }}"
        status_code: 200
        method: GET
        return_content: yes
      register: result_get_events_list
    
    - name: debug
      debug:
        var: result_get_events_list
   
    - name: Read users from CSV file and return a list
      read_csv:
        path: data.csv
      register: data_schedules
      delegate_to: localhost  
  
    - name: create event
      uri:
        url: "https://timetreeapis.com/calendars/{{ calender_id }}/events"
        headers:
          Accept: "application/vnd.timetree.v1+json"
          Authorization: "Bearer {{ access_token }}"
          Content-Type: "application/json"
        body_format: json
        body: '{"data":{"attributes":{"category":"schedule","title":"xx予定","all_day":false,"start_at":"{{ item.date }}T{{ item.startAt }}.000+09:00","start_timezone":"Asia/Tokyo","end_at":"{{ item.date }}T{{ item.endAt }}.000+09:00","end_timezone":"Asia/Tokyo","description":"{{item.description}}"},"relationships":{"label":{"data":{"id":"<CalenderID>,9","type":"label"}}}}}'
        status_code: 201
        method: POST
        return_content: yes
      register: result_create_event
      with_items: "{{ data_schedules.list }}"

    - name: debug
      debug:
        var: result_create_event
```

```csv:data.csv
NO,date,startAt,endAt,description
1,YYYY-MM-DD,hh:mm:ss,hh:mm:ss,zzzzzzzzzzzzzzzz
2,YYYY-MM-DD,hh:mm:ss,hh:mm:ss,zzzzzzzzzzzzzzzz
:
```

Ansibleで実行

```bash
#ansible-playbook createEvents.yml
```

変数やURL、POSTするデータを全て一つのyamlに記述したのでキレイではないが、手っ取り早く一括API実行ができた。また、データ（CSV）を変えることで同じ手順をミスなく繰り返すことができるようになった。  
エンタープライズでの運用では、運用対象がREST APIを持っている（Ansibleのモジュールはない）場合に、このようなデータだけが変わる定型運用を比較的簡単に自動化できる。

> 超私的なニーズ： 
> 在宅勤務が続き、小学生娘が何時に家に帰ってくるかを把握したいけど学校から配布されるプリントを見るのが面倒だったので。もちろん会社のAnsibleの私的利用は厳禁です。