Ansibleで複数のCatalystのパスワードを一括変更する

# 1.はじめに
Ansible 2.1 で ネットワーク関係のモジュールがコアモジュールになったので、
Cisco IOSに対応したモジュール「ios_command」や「ios_config」を利用して
パスワードの一括変更をやってみます

# 2.環境
- Ubuntu16.04
- Ansible 2.1 (apt-getでインストール)
- IOS関係モジュール（標準のまま）

```text
user@ubuntu-vm:/etc/ansible$ ansible-doc --list | grep ios
ios_command                        Run arbitrary commands on ios devices.
ios_config                         Manage Cisco IOS configuration sections
ios_template                       Manage Cisco IOS device configurations over SSH
iosxr_command                      Run arbitrary commands on ios devices.
iosxr_config                       Manage Cisco IOS XR configuration sections
iosxr_template                     Manage Cisco IOSXR device configurations over SSH
nagios                             Perform common tasks in Nagios related to downtime and notifications.
```

- Cisco Catalyst 3750 (IOS 12系) 2台

# 3.各ファイル
## 3.1. ansible.cfg
インストール直後から特に変更なし

## 3.2.インベントリファイル
```text:/etc/ansible/hosts
[cisco]        # Catalytのグループciscoを定義
192.168.1.1    # Catalyst 1台目
192.168.1.2    # Catalyst 2台目

[cisco:vars]   # グループcisco共通の変数定義
ansible_user=admin             # ログインユーザー
ansible_password=adminpas      # ログインパスワード
cisco_enable_secret=enable     # 特権パスワード
```

## 3.3.Playbook
```yaml:/etc/ansible/main.yml
---
- hosts: cisco        # インベントリファイルで定義したciscoグループが操作対象
  gather_facts: no
  connection: local

  tasks:
    - name: change password
      ios_config:
        lines:
          - username ope password opeope   # 実行させたいコマンド
        provider: "{{ cli }}"   # 後で定義する接続情報を辞書で渡す
      register: result          # 結果をデバッグ表示するため変数resultに登録
    - name: DEBUG
      debug: var=result         # 結果デバッグ

    - name: save config
      ios_command:
        commands:
          - write memory        # running-configの保存
        provider: "{{ cli }}"
      register: result
    - name: DEBUG
      debug: var=result

  vars:
    cli:   # 接続情報を辞書で定義（usernameとそれ以降はインベントリファイルから取得定義）
      host:     "{{ inventory_hostname }}"    # ホスト対象ホスト
      username: "{{ ansible_user }}"          # ログインユーザー
      password: "{{ ansible_password }}"      # ログインパスワード
      authorize: true                         # 特権モードに移行
      auth_pass: "{{ cisco_enable_secret }}"  # 特権パスワード

```



# 4.実行
## 4.1. 事前確認
SSH用にusernameを設定してありますので変更前を確認します。

```text:1台目(192.168.1.1)
SW1#show start | inc username
username ope password 7 011C6917641B03
```
```text:2台目(192.168.1.2)
SW2#show start | inc username
username ope password 7 61467B03003945
```

## 4.2. Playbook実行
```text
user@ubuntu-vm:/etc/ansible$ ansible-playbook main.yml

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

TASK [change password] *********************************************************
changed: [192.168.1.2]
changed: [192.168.1.1]

TASK [DEBUG] *******************************************************************
ok: [192.168.1.1] => {
    "result": {
        "changed": true,
        "responses": [
            ""
        ],
        "updates": [
            "username ope password opeope"
        ]
    }
}
ok: [192.168.1.2] => {
    "result": {
        "changed": true,
        "responses": [
            ""
        ],
        "updates": [
            "username ope password opeope"
        ]
    }
}

TASK [save config] *************************************************************
ok: [192.168.1.2]
ok: [192.168.1.1]

TASK [DEBUG] *******************************************************************
ok: [192.168.1.1] => {
    "result": {
        "changed": false,
        "stdout": [
            "Building configuration...\n[OK]"
        ],
        "stdout_lines": [
            [
                "Building configuration...",
                "[OK]"
            ]
        ]
    }
}
ok: [192.168.1.2] => {
    "result": {
        "changed": false,
        "stdout": [
            "Building configuration...\n[OK]"
        ],
        "stdout_lines": [
            [
                "Building configuration...",
                "[OK]"
            ]
        ]
    }
}

PLAY RECAP *********************************************************************
192.168.1.1               : ok=4    changed=1    unreachable=0    failed=0
192.168.1.2               : ok=4    changed=1    unreachable=0    failed=0
```
正常実行されたようです。

## 4.3. 事後確認
```text:1台目(192.168.1.1)
SW1#show start | inc username
username ope password 7 161615121D1B71
```
```text:2台目(192.168.1.2)
SW2#show start | inc username
username ope password 7 1416183E03182E
```
2台とも変更されました（値はダミーです）

# 5.補足
- 実用性より「なるほどネットワーク機器対応ってこういうことか」を体験するためにやってみたという趣旨です。
- 上記では省略していますが、Ansibleから接続する際のユーザー、パスワードは別に設定済みで、
今回パスワードを変更しているのは、また別のユーザーです。
- Playbookを複数回実行するとその都度変更コマンドが実行されます。実際は同じパスワードで設定していますが、冪等性は無いやり方です。
- 「ログとろうよ」「今どき write memory は無いわ」「変数の持ち方工夫したら？」など改善の余地しかないですが、今回はここまで・・。


# 6.参考情報
- [Network Modules](https://docs.ansible.com/ansible/list_of_network_modules.html)
 - モジュールの公式ドキュメント
- [ansible-playbook内でもYAMLのマージ記法が使えます! Cisco ios_commandモジュールなどでどうぞ。](http://qiita.com/tbuchi888/items/2ff64060290bcabc721e)
 - 接続情報を毎回書かなくて済むようにマージ記法という書き方で工夫されています。今回私はこの方法は使用せず、providerを使用した方法にしています。
- [【ansible】ansibleでCisco機器を制御してみる(サンプルコード1 config収集編)](http://qiita.com/onifinger/items/0a05faf175cc818fe447)
 - この記事を見て私も何かやってみようと思いました。local_actionの中でモジュールを呼び出していますが、今回私は少し違う方法でやってみました。
- [github privateip/Ansible-Webinar-Mar2016](https://github.com/privateip/Ansible-Webinar-Mar2016)
 - Webinarで使用したらしきPlaybook。いろいろ参考になります。