AnsibleでCisco IOSのVLANを設定してみる

# AnsibleでCisco IOSのVLANを設定してみる
そもそもAnsible触るの初めてなんですが、意外と便利に使えそうだったのでメモ。

ネットサーフィン（死語）しててios_vlanなるモジュールを見つけて便利そうだと思ったので使ってみました。
[ios_vlan - Manage VLANs on IOS network devices — Ansible Documentation](http://docs.ansible.com/ansible/devel/ios_vlan_module.html)

## ソースコードからAnsibleのインストール
ios_vlanモジュールはAnsible 2.5から使えるみたいです。
執筆時点(2017/12/6)ではpipやyum等で入る最新版は2.4なので、ソースコードから入れる必要があります。
（競合したりすると嫌なので、念のためpip/yum/aptで入れていたAnsibleは事前にremoveしておきました）

参考：[Ansible インストール - Qiita](https://qiita.com/KisaragiZin/items/5682370f5b63b398dbb1)

```
# ソースコード取ってくる(時間かかる、zipでダウンロードした方がいいかも）
$ git clone https://github.com/ansible/ansible.git
$ cd ansible

# CentOS/RHELの場合
# rpmの作成(必要なパッケージが入ってない場合怒られるので、都度いろいろとパッケージインストールしました)
# インストール(rpmのファイル名は毎回変わると思う)
$ make rpm
$ yum localinstall ./rpm-build/ansible-*.noarch.rpm

# 僕の環境はUbuntuだったのでこっち
# (install後にrebootしないとansibleコマンドがnot foundになりました)
$ make
$ make install
$ reboot
```

## 使ってみる
導入ができたら早速試しにこんな感じのplaybookを食わせます。([公式のドキュメント](http://docs.ansible.com/ansible/devel/ios_vlan_module.html)参照)

```:hosts
[l2sw]
172.16.0.2
```

```yaml:vlan.yaml
- hosts: l2sw
  remote_user: kamaboko
  connection: local
  tasks:
    - name: Create vlan
      ios_vlan:
        vlan_id: 120
        name: test-vlan
        state: present
    - name: Add interface to VLAN
      ios_vlan:
        vlan_id: 120
        interfaces:
          - GigabitEthernet0/4
          - GigabitEthernet0/5
    - name: change interface with VLAN
      ios_vlan:
        vlan_id: 3100
        interfaces:
          - GigabitEthernet0/2
```

さくっと実行。
ちなみに機器はCatalyst 2960G-8TC-Lを使ってます。SSH等は設定済み。
（自宅に余ってるスイッチが今それしかなかった）

```
salacia@Capella:~/tmp/ansible$ ansible-playbook -i hosts --ask-pass vlan.yaml
SSH password:

PLAY [l2sw] ***************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************
ok: [172.16.0.2]

TASK [Create vlan] ********************************************************************************************
changed: [172.16.0.2]

TASK [Add interface to VLAN] **********************************************************************************
changed: [172.16.0.2]

TASK [change interface with VLAN] *****************************************************************************
changed: [172.16.0.2]

PLAY RECAP ****************************************************************************************************
172.16.0.2                 : ok=4    changed=3    unreachable=0    failed=0

```

実行前

```
Switch#sh vlan

VLAN Name                             Status    Ports
---- -------------------------------- --------- -------------------------------
1    default                          active    Gi0/4, Gi0/5, Gi0/6, Gi0/7, Gi0/8
1002 fddi-default                     act/unsup
1003 token-ring-default               act/unsup
1004 fddinet-default                  act/unsup
1005 trnet-default                    act/unsup
3100 VLAN3100                         active    Gi0/2, Gi0/3

<snip>
```

実行後

```
Switch#sh vlan

VLAN Name                             Status    Ports
---- -------------------------------- --------- -------------------------------
1    default                          active    Gi0/3, Gi0/6, Gi0/7, Gi0/8
120  test-vlan                        active    Gi0/4, Gi0/5
1002 fddi-default                     act/unsup
1003 token-ring-default               act/unsup
1004 fddinet-default                  act/unsup
1005 trnet-default                    act/unsup
3100 VLAN3100                         active    Gi0/2

<snip>
```

でけた！
interfaceにVLAN設定したり外したりが簡単にできそうで便利かも。

**[追記] Trunk(tagged)は設定できなさそうです。残念。。**

**[さらに追記 2018/9/11] Trunk portの設定はios_interfaceモジュールで設定できる事がわかりました。**
本記事はversion 2.5ベースで書いていますが、v2.4から追加されたモジュールのようなので、v2.5でも使用できそうです。
[ios_interface](https://docs.ansible.com/ansible/latest/modules/ios_interface_module.html#ios-interface-module)

## 補足とか
### 機器について
今回の例ではCatalystを使用したのでうまくいきましたが、あまりうまく行かなかったのはルータの操作です。
具体的には手元の1812jで試験したところ、コマンドの違いで「show vlan」が使えないためにエラーになりました。
（1812jや881等では「show vlan-switch」というコマンドを使います）
モジュール自体まだ開発版なのでこれから対応する可能性もないわけではないと思いますが。
（issueとして報告すべきなのかも）

食わせたplaybookはちょっと違うけど、出てくるエラーメッセージ的にはこんな感じ。

```
fatal: [172.16.0.3]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "aggregate": null,
            "auth_pass": null,
            "authorize": null,
            "delay": 10,
            "host": null,
            "interfaces": null,
            "name": "vlan",
            "password": null,
            "port": null,
            "provider": {
                "auth_pass": null,
                "authorize": null,
                "host": null,
                "password": null,
                "port": null,
                "ssh_keyfile": null,
                "timeout": null,
                "username": null
            },
            "purge": false,
            "ssh_keyfile": null,
            "state": "present",
            "timeout": null,
            "username": null,
            "vlan_id": 120
        }
    },
    "msg": "show vlan\r\n% Ambiguous command:  \"show vlan\"\r\nMyRouter#",
    "rc": -32603
}
```

IOSはこのあたりの機器ごとの細かい違いのせいで、抽象化と自動化が難しいんだよなーってよく思います。。

### 感想
ネットワーク機器をAnsibleで制御するのは正直厳しいなぁと思ってますが、こういうVLANだけなど限定的な使い方なら使えそう。
（あとまだ触ってないですが、ios_interfaceも冪等性のあるshut/no shut操作ができるみたいで便利そうです。）
Ansibleのios_/iosxr_系のモジュールもっと増えてほしいなぁ。
（BGPとかOSPFとかをぜひおねがいします・・・）