Cisco IOS-XEのACLをRESTCONFで操作する(Ansible編)

# はじめに

[前回](https://qiita.com/tech_kitara/private/6bcc4d73f4499eca5212)の記事で、Cisco IOS-XEのACL操作をRESTCONFで行いました。前回は操作ツールとしてPythonを使いましたが、今回はAnsibleの`restconf_get`、`restconf_config`モジュールで簡単に試してみました。

AnsibleとRESTCONFの組み合わせは、公式ドキュメントに加え以下記事を参考にさせて頂きました。
[[Ansible] restconf_get モジュールで Cisco IOS XE のインターフェース情報を取得してみる](https://tekunabe.hatenablog.jp/entry/2019/05/02/ansble_restconf_get_ios)
[[Ansible] restconf_config モジュールで Cisco IOS XE のSyslogサーバー設定追加・削除してみる](https://tekunabe.hatenablog.jp/entry/2019/09/09/ansible_restconf_config_ios)

# 1. 用意した環境
Cisco DevNet Sandboxの[IOS XE on CSR Recommended Code](https://devnetsandbox.cisco.com/RM/Diagram/Index/d6ec9e7c-9cf1-488b-8f1d-876cd9f52cb4)のCSR1000v 16.9.3を利用させて頂きました。
Ansibleは2.9.0を使用しました。

# 2. Inventoryファイル
CSR1000vへRESTCONFでアクセスするための情報を定義します。

```text:inventory_restconf1.ini
[cisco]
csr1000v-1 ansible_host=[IPアドレス/ホスト名] ansible_user=[ユーザ名] ansible_password=[パスワード]

[cisco:vars]
ansible_connection=httpapi
ansible_network_os=restconf
ansible_httpapi_port=443
ansible_httpapi_use_ssl=yes
ansible_httpapi_validate_certs=no
```

# 3. ACLマージ・取得
まずACL設定が無い状態から、2つのACLを作成してみます。

## 3-1. Playbook
`restconf_config`モジュールを用い、`PATCH`メソッドでACL名`TEST`と`TEST2`をそれぞれ1行ずつ設定しました。
その後、`restconf_get`モジュールを用い、`GET`メソッドで拡張ACL情報を取得しました。

```yaml:playbook_restconf_create_acl3.yml
---

- hosts: cisco
  gather_facts: no

  tasks:
    - name: create new acl
      restconf_config:
        path: /data/Cisco-IOS-XE-native:native/ip
        method: patch
        content: "{{ content_data | to_json }}"
#        content: "{{ lookup('file', 'acl.json') }}"
      vars:
        content_data:
          Cisco-IOS-XE-native:ip:
            access-list:
              Cisco-IOS-XE-acl:extended:
                - access-list-seq-rule:
                  - ace-rule:
                      action: permit
                      dest-ipv4-address: 192.168.100.0
                      dest-mask: 0.0.0.255
                      ipv4-address: 192.168.4.0
                      mask: 0.0.0.255
                      protocol: ip
                    sequence: 30
                  name: TEST
                - access-list-seq-rule:
                  - ace-rule:
                      action: permit
                      dest-ipv4-address: 192.168.100.0
                      dest-mask: 0.0.0.255
                      ipv4-address: 192.168.7.0
                      mask: 0.0.0.255
                      protocol: ip
                    sequence: 70
                  name: TEST2

    - name: get acl info
      restconf_get:
        path: /data/Cisco-IOS-XE-native:native/ip/access-list/extended
      register: result

    - name: debug
      debug:
        msg: "{{ result }}"
```

## 3-2. 実行結果
想定通り2つのACLが作成されました。

```
$ ansible-playbook -i inventory_restconf1.ini playbook_restconf_create_acl3.yml

PLAY [cisco] **********************************************************************************************************

TASK [create new acl] *************************************************************************************************
changed: [csr1000v-1]

TASK [get acl info] ***************************************************************************************************
ok: [csr1000v-1]

TASK [debug] **********************************************************************************************************
ok: [csr1000v-1] => {
    "msg": {
        "changed": false,
        "failed": false,
        "response": {
            "Cisco-IOS-XE-acl:extended": [
                {
                    "access-list-seq-rule": [
                        {
                            "ace-rule": {
                                "action": "permit",
                                "dest-ipv4-address": "192.168.100.0",
                                "dest-mask": "0.0.0.255",
                                "ipv4-address": "192.168.4.0",
                                "mask": "0.0.0.255",
                                "protocol": "ip"
                            },
                            "sequence": "30"
                        }
                    ],
                    "name": "TEST"
                },
                {
                    "access-list-seq-rule": [
                        {
                            "ace-rule": {
                                "action": "permit",
                                "dest-ipv4-address": "192.168.100.0",
                                "dest-mask": "0.0.0.255",
                                "ipv4-address": "192.168.7.0",
                                "mask": "0.0.0.255",
                                "protocol": "ip"
                            },
                            "sequence": "70"
                        }
                    ],
                    "name": "TEST2"
                }
            ]
        }
    }
}

PLAY RECAP ************************************************************************************************************
csr1000v-1                 : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
```

# 4. ACL削除・取得
続いて、既存ACLの削除を行ってみます。

## 4-1. Playbook
`restconf_config`モジュールを用い、`DELETE`メソッドで先ほど作成した`TEST2`を削除しました。
その後、`restconf_get`モジュールを用い、`GET`メソッドで拡張ACL情報を取得しました。

```yaml:playbook_restconf_delete_acl.yml
---

- hosts: cisco
  gather_facts: no

  tasks:
    - name: delete acl
      restconf_config:
        path: /data/Cisco-IOS-XE-native:native/ip/access-list/extended=TEST2
        method: delete

    - name: get acl info
      restconf_get:
        path: /data/Cisco-IOS-XE-native:native/ip/access-list/extended
      register: result

    - name: debug
      debug:
        msg: "{{ result }}"
```

## 4-2. 出力結果
`TEST2`が削除され、`TEST`だけになった事が分かります。

```
$ ansible-playbook -i inventory_restconf1.ini playbook_restconf_delete_acl.yml

PLAY [cisco] **********************************************************************************************************

TASK [delete acl] *****************************************************************************************************
changed: [csr1000v-1]

TASK [get acl info] ***************************************************************************************************
ok: [csr1000v-1]

TASK [debug] **********************************************************************************************************
ok: [csr1000v-1] => {
    "msg": {
        "changed": false,
        "failed": false,
        "response": {
            "Cisco-IOS-XE-acl:extended": [
                {
                    "access-list-seq-rule": [
                        {
                            "ace-rule": {
                                "action": "permit",
                                "dest-ipv4-address": "192.168.100.0",
                                "dest-mask": "0.0.0.255",
                                "ipv4-address": "192.168.4.0",
                                "mask": "0.0.0.255",
                                "protocol": "ip"
                            },
                            "sequence": "30"
                        }
                    ],
                    "name": "TEST"
                }
            ]
        }
    }
}

PLAY RECAP ************************************************************************************************************
csr1000v-1                 : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
```

# 5. ACLリプレイス・取得
最後に、既存設定を上書きし、別のACLを作成してみます。

## 5-1. Playbook
`restconf_config`モジュールを用い、`PUT`メソッドでACL名`TEST3`を1行設定しました。
その後、`restconf_get`モジュールを用い、`GET`メソッドで拡張ACL情報を取得しました。

```yaml:playbook_restconf_create_acl.yml
---

- hosts: cisco
  gather_facts: no

  tasks:
    - name: create new acl
      restconf_config:
        path: /data/Cisco-IOS-XE-native:native/ip/access-list
        method: put
        content: "{{ content_data | to_json }}"
#        content: "{{ lookup('file', 'acl.json') }}"
      vars:
        content_data:
          Cisco-IOS-XE-native:access-list:
            Cisco-IOS-XE-acl:extended:
              - access-list-seq-rule:
                - ace-rule:
                    action: permit
                    dest-ipv4-address: 192.168.100.0
                    dest-mask: 0.0.0.255
                    ipv4-address: 192.168.9.0
                    mask: 0.0.0.255
                    protocol: ip
                  sequence: 30
                name: TEST3

    - name: get acl info
      restconf_get:
        path: /data/Cisco-IOS-XE-native:native/ip/access-list/extended
      register: result

    - name: debug
      debug:
        msg: "{{ result }}"
```

## 5-2. 出力結果
想定通り、`TEST3`のみ表示されました。

```
$ ansible-playbook -i inventory_restconf1.ini playbook_restconf_create_acl.yml

PLAY [cisco] **********************************************************************************************************

TASK [create new acl] *************************************************************************************************
changed: [csr1000v-1]

TASK [get acl info] ***************************************************************************************************
ok: [csr1000v-1]

TASK [debug] **********************************************************************************************************
ok: [csr1000v-1] => {
    "msg": {
        "changed": false,
        "failed": false,
        "response": {
            "Cisco-IOS-XE-acl:extended": [
                {
                    "access-list-seq-rule": [
                        {
                            "ace-rule": {
                                "action": "permit",
                                "dest-ipv4-address": "192.168.100.0",
                                "dest-mask": "0.0.0.255",
                                "ipv4-address": "192.168.9.0",
                                "mask": "0.0.0.255",
                                "protocol": "ip"
                            },
                            "sequence": "30"
                        }
                    ],
                    "name": "TEST3"
                }
            ]
        }
    }
}

PLAY RECAP ************************************************************************************************************
csr1000v-1                 : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
```

# 最後に
今回はPlaybookのサンプルのみになってしまいましたが、自動化の観点では、ACLマージ用Playbookの`Cisco-IOS-XE-acl:extended:`配下の変数をパラメーター表で定義し、`loop`で1行ずつ読み込んで設定変更する等が考えられると思います。